Untitled
plain_text
a month ago
6.3 kB
1
Indexable
Never
using cAlgo.API; using cAlgo.API.Indicators; using System; using System.Collections.Generic; namespace MovingAverageCrossoverBot { [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)] public class MovingAverageCrossoverBot : Robot { private TimeFrame higherTimeframe = TimeFrame.Daily; // Define the higher timeframe private double higherTimeframeThreshold = 0.5; private double desiredTradeVolume = 10000.0; // Desired trade volume in base currency units (e.g., for EURUSD) private double lotSize; private MovingAverage fastMA; private MovingAverage slowMA; private DateTime lastBarTime; private RelativeStrengthIndex rsi; private double riskPercentage = 2.0; private TradeResult openBuyPosition = null; private TradeResult openSellPosition = null; protected override void OnStart() { int rsiPeriod = 14; // Period for RSI calculation rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, rsiPeriod); // Configure your symbols and timeframes // TimeFrame timeframe = TimeFrame.HeikinHour; // Configure your moving average periods int fastMAPeriod = 50; int slowMAPeriod = 200; // Initialize moving averages fastMA = Indicators.MovingAverage(Bars.ClosePrices, fastMAPeriod, MovingAverageType.Simple); slowMA = Indicators.MovingAverage(Bars.ClosePrices, slowMAPeriod, MovingAverageType.Simple); lastBarTime = Bars.OpenTimes.LastValue; lotSize = Symbol.NormalizeVolumeInUnits(desiredTradeVolume); } protected override void OnTick() { if(Positions.Count == 0) { openBuyPosition = null; openSellPosition = null; } // Check if a new bar has formed if (Bars.OpenTimes.LastValue > lastBarTime) { lastBarTime = Bars.OpenTimes.LastValue; int index = Bars.ClosePrices.Count - 1; // Index of the last closed bar if (CrossesOnMultipleTimeframes() && fastMA.Result.HasCrossedAbove(slowMA.Result, index)&& openBuyPosition == null) { openBuyPosition = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.NormalizeVolumeInUnits(Symbol.LotSize), "Buy Order", 30, 10, null ); } if (CrossesOnMultipleTimeframesForSell() &&fastMA.Result.HasCrossedBelow(slowMA.Result, index)&& openSellPosition == null) { openSellPosition = ExecuteMarketOrder(TradeType.Sell, SymbolName, lotSize, "Sell Order", 30, 10, null); } } } private void ClosePosition(TradeResult position) { ClosePosition(position); } private bool CrossesOnMultipleTimeframes() { bool crossesOnFast = fastMA.Result.HasCrossedAbove(slowMA.Result, Bars.ClosePrices.Count - 1); bool crossesOnHigherTimeframe = CrossesOnTimeframe(higherTimeframe); // Confirm the signal by checking if both timeframes have a crossover return crossesOnFast && crossesOnHigherTimeframe; } private bool CrossesOnTimeframe(TimeFrame timeframe) { // Calculate moving averages on the specified timeframe manually double[] fastMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, 50); double[] slowMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, 200); int lastIndex = Bars.ClosePrices.Count - 1; bool crossesAbove = fastMASeries[lastIndex] > slowMASeries[lastIndex] && fastMASeries[lastIndex - 1] <= slowMASeries[lastIndex - 1]; bool crossesBelow = fastMASeries[lastIndex] < slowMASeries[lastIndex] && fastMASeries[lastIndex - 1] >= slowMASeries[lastIndex - 1]; // Use a threshold to confirm the crossover return crossesAbove && fastMASeries[lastIndex] > higherTimeframeThreshold || crossesBelow && fastMASeries[lastIndex] < 1 - higherTimeframeThreshold; } private bool CrossesOnMultipleTimeframesForSell() { bool crossesOnFast = fastMA.Result.HasCrossedBelow(slowMA.Result, Bars.ClosePrices.Count - 1); bool crossesOnHigherTimeframe = CrossesOnTimeframeForSell(higherTimeframe); // Confirm the signal by checking if both timeframes have a crossover return crossesOnFast && crossesOnHigherTimeframe; } private bool CrossesOnTimeframeForSell(TimeFrame timeframe) { // Calculate moving averages on the specified timeframe manually double[] fastMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, 50); double[] slowMASeries = CalculateSimpleMovingAverage(Bars.ClosePrices, 200); int lastIndex = Bars.ClosePrices.Count - 1; bool crossesAbove = fastMASeries[lastIndex] < slowMASeries[lastIndex] && fastMASeries[lastIndex - 1] >= slowMASeries[lastIndex - 1]; bool crossesBelow = fastMASeries[lastIndex] > slowMASeries[lastIndex] && fastMASeries[lastIndex - 1] <= slowMASeries[lastIndex - 1]; // Use a threshold to confirm the crossover return crossesAbove && fastMASeries[lastIndex] < 1 - higherTimeframeThreshold || crossesBelow && fastMASeries[lastIndex] > higherTimeframeThreshold; } private double[] CalculateSimpleMovingAverage(DataSeries source, int period) { double[] smaValues = new double[source.Count]; for (int i = 0; i < source.Count; i++) { if (i >= period - 1) { double sum = 0; for (int j = i - period + 1; j <= i; j++) { sum += source[j]; } smaValues[i] = sum / period; } else { smaValues[i] = source[i]; } } return smaValues; } } }