Smart Ass Trade is a multi-timeframe trend following strategy converted from the MQL implementation.
It analyzes MACD histogram (OsMA) and 20-period simple moving averages on 5, 15 and 30 minute charts.
A daily Williams %R filter blocks trades in overbought or oversold conditions.
Algorithm
Calculate MACD histogram and SMA(20) on 5m, 15m and 30m timeframes.
Define uptrend when histogram grows and SMA rises on all three timeframes.
Define downtrend when histogram declines and SMA falls on all three timeframes.
Use daily Williams %R (period 26) to avoid buying above -2 or selling below -98.
When all conditions align open a market order in the corresponding direction.
Position size can be fixed or optimized from account value.
Parameters
Hedging – allow opening opposite positions.
LotsOptimization – enable dynamic lot sizing.
Lots – fixed trading volume when optimization is off.
AutomaticTakeProfit – placeholder for dynamic take profit, currently unused.
MinimumTakeProfit – profit target in points for manual mode.
AutomaticStopLoss – placeholder for dynamic stop loss, currently unused.
StopLoss – stop loss in points for manual mode.
CandleType – base timeframe for subscriptions (default 5 minutes).
Notes
The strategy uses the high level API with SubscribeCandles and Bind calls.
Take profit and stop loss values are left for further extension; current version focuses on
signal generation and order execution.
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>
/// Smart trade strategy using EMA crossover.
/// </summary>
public class SmartAssTradeStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SmartAssTradeStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Parameters");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}