using System;
using cAlgo.API;
using cAlgo.API.Indicators;
namespace cAlgo
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SupertrendStrategy : Robot
{
private Supertrend supertrend10;
private Supertrend supertrend11;
private Supertrend supertrend12;
private ExponentialMovingAverage ema200;
private AverageTrueRange atr;
private DateTime lastTradeTime;
private BollingerBands bollingerBands;
private RelativeStrengthIndex rsi;
private OnBalanceVolume obv;
[Parameter("OBV Period", DefaultValue = 14)]
public int OBVPeriod { get; set; }
[Parameter("Supertrend Period (ATR 10)", DefaultValue = 10)]
public int SupertrendPeriod10 { get; set; }
[Parameter("Supertrend Multiplier (ATR 10)", DefaultValue = 1.0)]
public double SupertrendMultiplier10 { get; set; }
[Parameter("Supertrend Period (ATR 11)", DefaultValue = 11)]
public int SupertrendPeriod11 { get; set; }
[Parameter("Supertrend Multiplier (ATR 11)", DefaultValue = 2.0)]
public double SupertrendMultiplier11 { get; set; }
[Parameter("Supertrend Period (ATR 12)", DefaultValue = 12)]
public int SupertrendPeriod12 { get; set; }
[Parameter("Supertrend Multiplier (ATR 12)", DefaultValue = 3.0)]
public double SupertrendMultiplier12 { get; set; }
[Parameter("RSI Period", DefaultValue = 14)]
public int RSIPeriod { get; set; }
[Parameter("RSI Overbought Level", DefaultValue = 70)]
public int RSIOverboughtLevel { get; set; }
[Parameter("RSI Oversold Level", DefaultValue = 30)]
public int RSIOversoldLevel { get; set; }
private MacdHistogram macdHistogram;
[Parameter("MACD Fast EMA Period", DefaultValue = 12)]
public int MacdFastPeriod { get; set; }
[Parameter("MACD Slow EMA Period", DefaultValue = 26)]
public int MacdSlowPeriod { get; set; }
[Parameter("MACD Signal Smoothing Period", DefaultValue = 9)]
public int MacdSignalPeriod { get; set; }
[Parameter("EMA 200 Period", DefaultValue = 200)]
public int EMA200Period { get; set; }
[Parameter("ATR Period", DefaultValue = 14)]
public int ATRPeriod { get; set; }
[Parameter("Volume (Lots)", DefaultValue = 1.0)]
public double Volume { get; set; }
[Parameter("Trade Cooldown (Minutes)", DefaultValue = 360)]
public int TradeCooldownMinutes { get; set; }
[Parameter("Bollinger Bands Period", DefaultValue = 20)]
public int BollingerPeriod { get; set; }
[Parameter("Bollinger Bands Deviation", DefaultValue = 2.0)]
public double BollingerDeviation { get; set; }
public DataSeries Source { get; set; }
[Output("Main")]
private double trailingStopDistanceInPips = 10;
private double minProfitForTrailing = 10; // Minimum profit in pips before trailing stop becomes active
private Color currentStopLossColor;
private Color regularStopLossColor = Color.Red;
private Color trailingStopLossColor = Color.Blue;
private DateTime lastTime;
private DateTime entryTime;
private Position lastTrade;
protected override void OnStart()
{
supertrend10 = Indicators.Supertrend(SupertrendPeriod10, SupertrendMultiplier10);
supertrend11 = Indicators.Supertrend(SupertrendPeriod11, SupertrendMultiplier11);
supertrend12 = Indicators.Supertrend(SupertrendPeriod12, SupertrendMultiplier12);
bollingerBands = Indicators.BollingerBands(MarketSeries.Close, BollingerPeriod, BollingerDeviation, MovingAverageType.Simple);
ema200 = Indicators.ExponentialMovingAverage(MarketSeries.Close, EMA200Period);
atr = Indicators.AverageTrueRange(ATRPeriod, MovingAverageType.Simple);
lastTradeTime = MarketSeries.OpenTime.LastValue;
rsi = Indicators.RelativeStrengthIndex(MarketSeries.Close, RSIPeriod);
macdHistogram = Indicators.MacdHistogram(MarketSeries.Close, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod);
obv = Indicators.OnBalanceVolume(Source);
}
protected override void OnBar()
{
foreach (var position in Positions)
{
double unrealizedProfitInPips = position.Pips;
if (unrealizedProfitInPips >= minProfitForTrailing)
{
double trailingStopPrice = Symbol.Bid - trailingStopDistanceInPips * Symbol.PipSize;
ModifyPosition(position, trailingStopPrice, position.TakeProfit);
currentStopLossColor = trailingStopLossColor;
}
}
int lastIndex = MarketSeries.Close.Count - 1;
// Calculate the highest high and lowest low within a specified period
int lookbackPeriod = 300; // Adjust the period as needed
double highestHigh = MarketSeries.High.Maximum(lookbackPeriod);
double lowestLow = MarketSeries.Low.Minimum(lookbackPeriod);
// Check conditions for Supertrend 10 (ATR 10, Multiplier 1)
bool isUpTrend10 = supertrend10.UpTrend.IsRising();
bool isDownTrend10 = supertrend10.DownTrend.IsFalling();
// Check conditions for Supertrend 11 (ATR 11, Multiplier 2)
bool isUpTrend11 = supertrend11.UpTrend.IsRising();
bool isDownTrend11 = supertrend11.DownTrend.IsFalling();
// Check conditions for Supertrend 12 (ATR 12, Multiplier 3)
bool isUpTrend12 = supertrend12.UpTrend.IsRising();
bool isDownTrend12 = supertrend12.DownTrend.IsFalling();
// Check if the last 10 bars were above SMA for buy trade
bool isAboveSMA10 = IsAboveSMA(MarketSeries.Close, lastIndex, 5);
// Check if the last 10 bars were below SMA for sell trade
bool isBelowSMA10 = IsBelowSMA(MarketSeries.Close, lastIndex, 5);
// Check Bollinger Bands conditions
bool isAboveUpperBand = MarketSeries.Close[lastIndex] > bollingerBands.Top[lastIndex];
bool isBelowLowerBand = MarketSeries.Close[lastIndex] < bollingerBands.Bottom[lastIndex];
// Calculate the OBV values for the previous and current bars
double prevOBV = obv.Result[1];
double currentOBV = obv.Result[0];
double minATR = 10.0; // Set your desired minimum ATR value
bool hasMinATR = atr.Result[lastIndex] > minATR;
// Check OBV conditions
bool isBullishOBV = currentOBV > prevOBV && prevOBV > obv.Result[1];
bool isBearishOBV = currentOBV < prevOBV && prevOBV < obv.Result[2];
// Check if the market is in a range-bound condition
bool isMarketInARange = IsMarketInARange(lastIndex, 300); // Adjust the period as needed
// Calculate the range as a percentage of the Average True Range (ATR)
double atrValue = atr.Result[lastIndex];
double range = (highestHigh - lowestLow) / atrValue;
// Define a threshold for how close to the highest high or lowest low you want to avoid trading
double avoidThreshold = 0.2; // Example threshold, adjust as needed
// Check if the market is close to the highest high or lowest low
bool isCloseToHighestHigh = MarketSeries.Close[lastIndex] > highestHigh - (atrValue * avoidThreshold);
bool isCloseToLowestLow = MarketSeries.Close[lastIndex] < lowestLow + (atrValue * avoidThreshold);
double SLtargets = 20;
double TPtargets = 100;
// Close buy positions if at least one Supertrend turns red or if the last 10 bars were below SMA
if ( (isDownTrend10 || isDownTrend11 || isDownTrend12 || isBelowSMA10))
{
foreach (var position in Positions)
{
if (position.TradeType == TradeType.Buy)
lastTime = DateTime.Now;
lastTrade = position;
ClosePosition(position);
}
}
// Calculate the highest high and lowest low within specified periods
int lookbackPeriod8Hour = 480; // 8-hour
int lookbackPeriodDay = 1440; // day
int lookbackPeriod30Min = 30; // 30 minutes
double highestHigh8Hour = MarketSeries.High.Maximum(lookbackPeriod8Hour);
double lowestLow8Hour = MarketSeries.Low.Minimum(lookbackPeriod8Hour);
double highestHighDay = MarketSeries.High.Maximum(lookbackPeriodDay);
double lowestLowDay = MarketSeries.Low.Minimum(lookbackPeriodDay);
double highestHigh30Min = MarketSeries.High.Maximum(lookbackPeriod30Min);
double lowestLow30Min = MarketSeries.Low.Minimum(lookbackPeriod30Min);
// Check if all specified timeframes are in a downtrend
bool is8HourDowntrend = IsDowntrend(lookbackPeriod8Hour);
bool isDayDowntrend = IsDowntrend(lookbackPeriodDay);
bool is30MinDowntrend = IsDowntrend(lookbackPeriod30Min);
// Avoid trading if all specified timeframes are in a downtrend
if ( is8HourDowntrend || isDayDowntrend)
{
Print("Avoiding trade due to downtrend in all timeframes.");
return;
}
// Open new positions for buy trade if all Supertrends are rising, and the last 10 bars were above SMA
if (Positions.Count == 0 &&
isUpTrend10 && isUpTrend11 && isUpTrend12 &&
isAboveSMA10 &&
isAboveUpperBand &&
// !isMarketInARange&&
// !isCloseToHighestHigh &&
// isBullishOBV &&
hasMinATR
//&& rsi.Result[lastIndex] < 40
)
{
// Buy signal (All Supertrends are rising, and the last 10 bars were above SMA)
ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.NormalizeVolumeInUnits(Symbol.LotSize), "Buy Order", SLtargets, TPtargets);
}
// else if( Positions.Count < 1 &&
// isDownTrend10 && isDownTrend11 && isDownTrend12 &&
// isBelowSMA10 &&
// !isMarketInARange&&
// isBullishOBV &&
// hasMinATR
//&& rsi.Result[lastIndex] < 40
// )
// {
// Buy signal (All Supertrends are rising, and the last 10 bars were above SMA)
// ExecuteMarketOrder(TradeType.Sell, SymbolName, Symbol.NormalizeVolumeInUnits(Symbol.LotSize), "Sell Order", SLtargets, TPtargets);
// }
}
private bool IsDowntrend(int lookbackPeriod)
{
double highestHigh = MarketSeries.High.Maximum(lookbackPeriod);
double lowestLow = MarketSeries.Low.Minimum(lookbackPeriod);
return MarketSeries.Close.LastValue < lowestLow;
}
private bool IsMarketInARange(int index, int period)
{
// Calculate the range by finding the highest and lowest prices within the specified period
double highestHigh = MarketSeries.High.Maximum(period);
double lowestLow = MarketSeries.Low.Minimum(period);
// Calculate the range as a percentage of ATR (you can adjust this threshold)
double rangeThreshold = 1.5; // Example threshold, adjust as needed
double atrValue = atr.Result[index];
double range = (highestHigh - lowestLow) / atrValue;
return range <= rangeThreshold;
}
private bool IsAboveSMA(DataSeries series, int index, int period)
{
for (int i = 0; i < period; i++)
{
if (series[index - i] <= ema200.Result[index - i])
{
return false;
}
}
return true;
}
private bool IsBelowSMA(DataSeries series, int index, int period)
{
for (int i = 0; i < period; i++)
{
if (series[index - i] >= ema200.Result[index - i])
{
return false;
}
}
return true;
}
}
}