Auf GitHub ansehen

ASCtrend Strategy

This strategy uses the Williams %R indicator to detect rapid reversals similar to the ASCtrend approach. It sells when the indicator rises from an oversold level to an overbought level and buys when the opposite occurs.

Details

  • Entry Criteria:
    • Sell when Williams %R crosses from oversold (below x2) to overbought (above x1).
    • Buy when Williams %R crosses from overbought (above x1) to oversold (below x2).
  • Long/Short: Both.
  • Exit Criteria:
    • Reverse signal closes and flips the position.
  • Stops: No.
  • Default Values:
    • Risk = 4
    • CandleType = 1 hour
  • Filters:
    • Category: Reversal
    • Direction: Both
    • Indicators: Williams %R
    • Stops: No
    • Complexity: Low
    • Timeframe: Any
    • Seasonality: No
    • Neural networks: No
    • Divergence: No
    • Risk level: Medium
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// ASCtrend strategy based on Williams %R reversals.
/// </summary>
public class ASCtrendStrategy : Strategy
{
	private readonly StrategyParam<int> _risk;
	private readonly StrategyParam<DataType> _candleType;

	private bool _wasOversold;
	private bool _wasOverbought;

	/// <summary>
	/// Risk factor that adjusts threshold levels.
	/// </summary>
	public int Risk
	{
		get => _risk.Value;
		set => _risk.Value = value;
	}

	/// <summary>
	/// Candle type used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize the strategy.
	/// </summary>
	public ASCtrendStrategy()
	{
		_risk = Param(nameof(Risk), 4)
			.SetRange(1, 50)
			.SetDisplay("Risk", "Risk parameter", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_wasOversold = false;
		_wasOverbought = false;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var wpr = new WilliamsR
		{
			Length = 3 + Risk * 2
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(wpr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, wpr);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal wpr)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var value2 = 100m - Math.Abs(wpr);
		var x1 = 67m + Risk;
		var x2 = 33m - Risk;

		if (value2 < x2)
			_wasOversold = true;
		else if (value2 > x1)
			_wasOverbought = true;

		if (_wasOversold && value2 > x1 && Position >= 0)
		{
			SellMarket();
			_wasOversold = false;
			_wasOverbought = false;
			return;
		}

		if (_wasOverbought && value2 < x2 && Position <= 0)
		{
			BuyMarket();
			_wasOversold = false;
			_wasOverbought = false;
		}
	}
}