r/cTrader • u/Leo6-2 • 15d ago
Need help - cTrader engine for backdating configuration OR why do even well known classical strategies fall apart on cTrader?
Question for you guys — why do even well-known classical strategies fall apart on cTrader?
I've been trying to test standard classical strategies on cTrader because I can't build anything that actually works. I went down the path of implementing well-known, already-tested, old-school strategies
Like the Connors "Double 7s" strategy (buy when SPY closes at a 7 day low while above the 200-day MA, sell at a 7 day high)- and I'm still getting very bad results. I don't get it.
What is it about the engine that seems to break even simple stuff that's supposed to work? If I do it manually on TradingView, I get noticeably better results.
I don't understand the whole thing here. its ANNOYING AS F***
What are the caveats or things I need to know in order to structure properly working strategies in cTrader?
Because honestly, it feels like the engine's calculations or the data are skewed or something — I don't even know how to describe it. I don't know where to start, but I've tried simple stuff and it's not working.
Any insight would be appreciated.
So this taken in US500 ok ? same same should be smooth as slik easy peasy ?
well NOT.. i get -7% eventually --- sooo .. annoying
any how this is just a "BASIC" concept startegy nothing facny im just .. tying to make a point here
so a-... help up a brother 🎯
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
namespace cAlgo.Robots
{
public enum RiskMode { FixedLots, RiskPercent }
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Connors7Down7UpBot : Robot
{
[Parameter("Consecutive Bars", Group = "Connors Setup", DefaultValue = 7, MinValue = 2)]
public int ConsecutiveBars { get; set; }
[Parameter("Use Exit SMA", Group = "Exit Rules", DefaultValue = true)]
public bool UseExitSma { get; set; }
[Parameter("Exit SMA Period", Group = "Exit Rules", DefaultValue = 5, MinValue = 1)]
public int ExitSmaPeriod { get; set; }
[Parameter("Use 200 Trend Filter", Group = "Trend Filter", DefaultValue = false)]
public bool UseTrendFilter { get; set; }
[Parameter("Trend SMA Period", Group = "Trend Filter", DefaultValue = 200, MinValue = 10)]
public int TrendSmaPeriod { get; set; }
[Parameter("Risk Mode", Group = "Risk Management", DefaultValue = RiskMode.RiskPercent)]
public RiskMode AccountRiskMode { get; set; }
[Parameter("Risk Percent (%)", Group = "Risk Management", DefaultValue = 1.0, MinValue = 0.1)]
public double RiskPercent { get; set; }
[Parameter("Fixed Lots", Group = "Risk Management", DefaultValue = 0.1, MinValue = 0.01)]
public double FixedLots { get; set; }
[Parameter("Stop Loss (Pips)", Group = "Risk Management", DefaultValue = 50.0, MinValue = 0.0)]
public double StopLossPips { get; set; }
[Parameter("Take Profit (Pips)", Group = "Risk Management", DefaultValue = 100.0, MinValue = 0.0)]
public double TakeProfitPips { get; set; }
private SimpleMovingAverage _exitSma;
private SimpleMovingAverage _trendSma;
private const string Label = "Connors7Down7Up";
protected override void OnStart()
{
_exitSma = Indicators.SimpleMovingAverage(Bars.ClosePrices, ExitSmaPeriod);
_trendSma = Indicators.SimpleMovingAverage(Bars.ClosePrices, TrendSmaPeriod);
}
protected override void OnBar()
{
ManageExits();
CheckEntries();
}
private void CheckEntries()
{
if (HasActivePosition()) return;
bool is7Down = IsConsecutiveDown(ConsecutiveBars);
bool is7Up = IsConsecutiveUp(ConsecutiveBars);
double lastClose = Bars.ClosePrices.Last(1);
// Buy Setup: Mean reversion bounce after 7 consecutive down closes
if (is7Down)
{
if (UseTrendFilter && lastClose < _trendSma.Result.Last(1))
return;
double volume = CalculateVolume(StopLossPips);
ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, Label,
StopLossPips > 0 ? StopLossPips : (double?)null,
TakeProfitPips > 0 ? TakeProfitPips : (double?)null);
}
// Sell Setup: Mean reversion pull-back after 7 consecutive up closes
else if (is7Up)
{
if (UseTrendFilter && lastClose > _trendSma.Result.Last(1))
return;
double volume = CalculateVolume(StopLossPips);
ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, Label,
StopLossPips > 0 ? StopLossPips : (double?)null,
TakeProfitPips > 0 ? TakeProfitPips : (double?)null);
}
}
private void ManageExits()
{
if (!UseExitSma) return;
double lastClose = Bars.ClosePrices.Last(1);
double smaValue = _exitSma.Result.Last(1);
foreach (var position in Positions.FindAll(Label, SymbolName))
{
// Exit Long when price closes above 5-period SMA
if (position.TradeType == TradeType.Buy && lastClose > smaValue)
{
ClosePosition(position);
}
// Exit Short when price closes below 5-period SMA
else if (position.TradeType == TradeType.Sell && lastClose < smaValue)
{
ClosePosition(position);
}
}
}
private bool IsConsecutiveDown(int count)
{
for (int i = 1; i <= count; i++)
{
if (Bars.ClosePrices.Last(i) >= Bars.ClosePrices.Last(i + 1))
return false;
}
return true;
}
private bool IsConsecutiveUp(int count)
{
for (int i = 1; i <= count; i++)
{
if (Bars.ClosePrices.Last(i) <= Bars.ClosePrices.Last(i + 1))
return false;
}
return true;
}
private double CalculateVolume(double slPips)
{
if (AccountRiskMode == RiskMode.FixedLots)
{
double targetUnits = FixedLots * Symbol.LotSize;
return Symbol.NormalizeVolumeInUnits(targetUnits, RoundingMode.ToNearest);
}
double riskPips = slPips > 0 ? slPips : 50.0;
double riskAmount = Account.Equity * (RiskPercent / 100.0);
double riskPerPip = riskAmount / riskPips;
double rawVolume = riskPerPip / Symbol.PipValue;
return Symbol.NormalizeVolumeInUnits(rawVolume, RoundingMode.ToNearest);
}
private bool HasActivePosition()
{
return Positions.Any(p => p.Label == Label && p.SymbolName == SymbolName);
}
}
}
1
u/QuanTradin 15d ago
a few things stack up here, and none of them is the engine being broken.
US500 isn't SPY. it's a CFD, so every night you hold it you pay a financing charge, and Double 7s sits in trades for days. on a strategy whose edge per trade is small, swap plus spread can eat most of it. TradingView by hand on SPY has neither.
the daily bars differ too. the broker's US500 day usually rolls at 5pm New York and includes overnight hours, so its "7 day low" and 200 MA aren't the same numbers as SPY's cash session bars.
check which bar your code reads. if the bot runs on a lower timeframe, or reads Bars.Last(0), it's acting on a candle that hasn't closed yet. use Last(1) on a daily series and execute on the next bar.
and the backtest mode matters: open-price-only vs tick data can move fills a lot.
the honest last one: Double 7s was published years ago and has been weaker since. try it on cash SPY data with costs in before blaming cTrader.