Countertrend Strategy with Quoting
Overview
StairsCountertrendStrategy
is a countertrend trading strategy that opens positions against an established trend of a specific length, using a quoting mechanism for more precise market entry.
Main Components
public class StairsCountertrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleDataType;
private readonly StrategyParam<int> _length;
private QuotingProcessor _quotingProcessor;
private int _bullLength;
private int _bearLength;
}
Strategy Parameters
The strategy allows customizing the following parameters:
- CandleDataType - candle type to work with (default 1-minute)
- Length - number of consecutive candles in one direction to identify a trend (default 5)
The Length parameter is available for optimization in the range from 2 to 10 with a step of 1.
Strategy Initialization
In the OnStarted method, counters are reset, candle subscription is created, and visualization is prepared:
protected override void OnStarted(DateTimeOffset time)
{
// Reset counters at start
_bullLength = 0;
_bearLength = 0;
// Create candle subscription
var subscription = SubscribeCandles(CandleDataType);
subscription
.Bind(ProcessCandle)
.Start();
// Set up visualization on the chart
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
base.OnStarted(time);
}
Processing Candles
The ProcessCandle
method is called for each completed candle and implements the logic for trend detection and quoting processor management:
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Identify bullish or bearish candle
if (candle.OpenPrice < candle.ClosePrice)
{
_bullLength++;
_bearLength = 0;
this.AddInfoLog($"Bullish candle detected. Streak: {_bullLength}");
}
else if (candle.OpenPrice > candle.ClosePrice)
{
_bullLength = 0;
_bearLength++;
this.AddInfoLog($"Bearish candle detected. Streak: {_bearLength}");
}
// Stop existing processor when direction change is needed
if (_quotingProcessor != null)
{
// Check if processor needs to be cleared (trend change or position)
var shouldClearProcessor = false;
// Need to sell if bullish trend and no short position
if (_bullLength >= Length && Position >= 0)
shouldClearProcessor = true;
// Need to buy if bearish trend and no long position
else if (_bearLength >= Length && Position <= 0)
shouldClearProcessor = true;
if (shouldClearProcessor)
{
_quotingProcessor?.Dispose();
_quotingProcessor = null;
}
}
// Create new quoting processor when needed
if (_quotingProcessor == null && IsFormedAndOnlineAndAllowTrading())
{
if (_bullLength >= Length && Position >= 0)
{
// Bullish trend - open short position
CreateQuotingProcessor(Sides.Sell);
this.AddInfoLog($"Starting SELL quoting after {_bullLength} bullish candles");
}
else if (_bearLength >= Length && Position <= 0)
{
// Bearish trend - open long position
CreateQuotingProcessor(Sides.Buy);
this.AddInfoLog($"Starting BUY quoting after {_bearLength} bearish candles");
}
}
}
Creating Quoting Processor
The CreateQuotingProcessor
method creates a quoting processor with the specified direction:
private void CreateQuotingProcessor(Sides side)
{
// Create behavior for market quoting
var behavior = new MarketQuotingBehavior(
0, // No price offset
new Unit(0.1m, UnitTypes.Percent), // Use 0.1% as minimum deviation
MarketPriceTypes.Following // Follow market price
);
// Create quoting processor
_quotingProcessor = new(
behavior,
Security,
Portfolio,
side,
Volume, // Quoting volume
Volume, // Maximum order volume
TimeSpan.Zero, // No timeout
this, // Strategy implements ISubscriptionProvider
this, // Strategy implements IMarketRuleContainer
this, // Strategy implements ITransactionProvider
this, // Strategy implements ITimeProvider
this, // Strategy implements IMarketDataProvider
IsFormedAndOnlineAndAllowTrading, // Check trading permission
true, // Use order book prices
true // Use last trade price if order book is empty
)
{
Parent = this
};
// Subscribe to processor events
_quotingProcessor.OrderRegistered += order =>
this.AddInfoLog($"Order {order.TransactionId} registered at price {order.Price}");
_quotingProcessor.OrderFailed += fail =>
this.AddInfoLog($"Order failed: {fail.Error.Message}");
_quotingProcessor.OwnTrade += trade =>
this.AddInfoLog($"Trade executed: {trade.Trade.Volume} at {trade.Trade.Price}");
_quotingProcessor.Finished += isOk =>
{
_quotingProcessor?.Dispose();
_quotingProcessor = null;
};
// Initialize processor
_quotingProcessor.Start();
}
Trading Logic
- Sell signal:
Length
consecutive bullish candles (close price above open price) when there is no short position - Buy signal:
Length
consecutive bearish candles (close price below open price) when there is no long position - Quoting processor is used for market entry, following the market price
Features
- The strategy automatically determines instruments to work with via the
GetWorkingSecurities()
method - The strategy only works with completed candles
- Quoting is used instead of market orders for more efficient market entry
- The strategy applies a countertrend approach, opening positions against the established trend
- Detailed logging of main events for debugging is implemented
- The quoting processor is automatically cleared when the trend direction changes or when targets are reached
- Candles and trades visualization on the chart is supported
- The sequence length parameter optimization is implemented for strategy configuration