Strategy that trades based on where a candle opens and closes within its range.
Enters long when the candle opens near its low and closes near its high, showing strong bullish pressure.
Enters short when the candle opens near its high and closes near its low, indicating strong bearish pressure.
The approach relies purely on price action and can be applied to any liquid market.
Details
Entry Criteria:
Long: Open near Low && Close near High
Short: Open near High && Close near Low
Long/Short: Both
Exit Criteria: Opposite signal
Stops: No
Default Values:
BodyThreshold = 0.2m
CandleType = TimeSpan.FromMinutes(5).TimeFrame()
Filters:
Category: Candlestick pattern
Direction: Both
Indicators: None
Stops: No
Complexity: Basic
Timeframe: Intraday
Seasonality: No
Neural Networks: No
Divergence: No
Risk Level: Medium
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Candle Body Shapes strategy.
/// "Near" means within BodyThreshold of the candle range. A candle that opens near its low and closes near its high goes long,
/// one that opens near its high and closes near its low goes short; the opposite signal reverses the position.
/// </summary>
public class CandleBodyShapesStrategy : Strategy
{
private readonly StrategyParam<decimal> _bodyThreshold;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Fraction of the candle range that counts as near its high or low.
/// </summary>
public decimal BodyThreshold
{
get => _bodyThreshold.Value;
set => _bodyThreshold.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public CandleBodyShapesStrategy()
{
_bodyThreshold = Param(nameof(BodyThreshold), 0.2m)
.SetRange(0m, 1m)
.SetDisplay("Body Threshold", "Fraction of the candle range that counts as near its high or low", "Pattern");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0)
return;
var near = BodyThreshold * range;
var openNearLow = candle.OpenPrice - candle.LowPrice <= near;
var openNearHigh = candle.HighPrice - candle.OpenPrice <= near;
var closeNearLow = candle.ClosePrice - candle.LowPrice <= near;
var closeNearHigh = candle.HighPrice - candle.ClosePrice <= near;
if (openNearLow && closeNearHigh && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (openNearHigh && closeNearLow && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class candle_body_shapes_strategy(Strategy):
"""
Candle Body Shapes strategy.
"Near" means within BodyThreshold of the candle range. A candle that opens near its low and closes near its high goes long,
one that opens near its high and closes near its low goes short; the opposite signal reverses the position.
"""
def __init__(self):
super(candle_body_shapes_strategy, self).__init__()
self._body_threshold = self.Param("BodyThreshold", 0.2).SetRange(0.0, 1.0).SetDisplay("Body Threshold", "Fraction of the candle range that counts as near its high or low", "Pattern")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(candle_body_shapes_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
price_range = candle.HighPrice - candle.LowPrice
if price_range <= 0:
return
near = Decimal(self._body_threshold.Value) * price_range
open_near_low = candle.OpenPrice - candle.LowPrice <= near
open_near_high = candle.HighPrice - candle.OpenPrice <= near
close_near_low = candle.ClosePrice - candle.LowPrice <= near
close_near_high = candle.HighPrice - candle.ClosePrice <= near
if open_near_low and close_near_high and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif open_near_high and close_near_low and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return candle_body_shapes_strategy()