Cbot incorrectly opens/closes positions.

Created at 14 Jun 2023, 20:41
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
KJ

KJtech

Joined 14.06.2023

Cbot incorrectly opens/closes positions.
14 Jun 2023, 20:41


Hello. Need help correcting the code. I would like the cBot to close / open the position after the EMA cut, but only after the close of the candle during which the cut occurred, and not immediately. I use renko candles. Cbot also has an error and when closing / opening a position, it closes all positions that are currently open, which I manually opened. It only has to close/open its own positions. Please help.

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using System.IO;
using System.Linq;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class TradingStrategiesBot : Robot
    {
        [Parameter("Fast Moving Average Period",Group = "Moving Average", DefaultValue = 10, MinValue = 1)]
        public int FastMAPeriod { get; set; }
        

        [Parameter("Lot Size", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double LotSize { get; set; }

        [Parameter("Slow Moving Average Period",Group = "Moving Average", DefaultValue = 30, MinValue = 1)]
        public int SlowMAPeriod { get; set; }

        [Parameter("ATR Stoploss", DefaultValue = 100, MinValue = 1)]
        public int StopLoss { get; set; }

        [Parameter("ATR TakeProfit", DefaultValue = 200, MinValue = 1)]
        public int TakeProfit { get; set; }

        [Parameter("Enable Trailing Stop Loss")]
        public bool EnableTrailingStopLoss { get; set; }

        [Parameter("Enable Take Profit")]
        public bool EnableTakeProfit { get; set; }

        [Parameter("Enable Stop Loss")]
        public bool EnableStopLoss { get; set; }

        [Parameter("Strategy Type")]
        public StrategyType Strategy { get; set; }
        
        [Parameter("Moving Average Type",Group = "Moving Average")]
        public MovingAverageType matype { get; set; }
        
        [Parameter("Fast MA Source", Group = "Moving Average")]
        public DataSeries fSource { get; set; }
        
        [Parameter("Slow MA Source", Group = "Moving Average")]
        public DataSeries sSource { get; set; }
        
        
        [Parameter("Start Time (HH:MM)", DefaultValue = "00:00")]
        public string StartTime { get; set; }

        [Parameter("Stop Time (HH:MM)", DefaultValue = "23:59")]
        public string StopTime { get; set; }

        [Parameter("Close All Positions At (HH:MM)", DefaultValue = "")]
        public string ClosePositionsAt { get; set; }
        


        private MovingAverage _fastMA;
        private MovingAverage _slowMA;
        private AverageTrueRange atr;
        private TimeSpan _startTime;
        private TimeSpan _stopTime;
        private TimeSpan? _closePositionsAtTime;


        protected override void OnStart()
        {
            _fastMA = Indicators.MovingAverage(fSource, FastMAPeriod, matype);
            _slowMA = Indicators.MovingAverage(sSource, SlowMAPeriod, matype);
            Chart.DrawStaticText("Copyright", "Owned by Singularity", VerticalAlignment.Top, HorizontalAlignment.Left, "Gray");
            atr = Indicators.AverageTrueRange(14, MovingAverageType.Exponential);
            
                        if (!TimeSpan.TryParse(StartTime, out _startTime))
            {
                Print("Invalid Start Time format. Use HH:MM format.");
                Stop();
            }

            if (!TimeSpan.TryParse(StopTime, out _stopTime))
            {
                Print("Invalid Stop Time format. Use HH:MM format.");
                Stop();
            }

            if (!string.IsNullOrEmpty(ClosePositionsAt))
            {
                TimeSpan closePositionsAtTime;
                if (TimeSpan.TryParse(ClosePositionsAt, out closePositionsAtTime))
                {
                    _closePositionsAtTime = closePositionsAtTime;
                }
                else
                {
                    Print("Invalid Close All Positions At format. Use HH:MM format.");
                    Stop();
                }
            }
        }

        protected override void OnBar()
        {
            var currentTime = Server.Time.TimeOfDay;

            if (currentTime >= _startTime && currentTime <= _stopTime)
            {
                if (_fastMA.Result.HasCrossedAbove(_slowMA.Result, 1))
                {
                    ExecuteStrategy(TradeType.Buy);
                }
                else if (_fastMA.Result.HasCrossedBelow(_slowMA.Result, 1))
                {
                    ExecuteStrategy(TradeType.Sell);
                }
            }

            if (_closePositionsAtTime.HasValue && currentTime >= _closePositionsAtTime.Value)
            {
                CloseAllPositions();
            }
        }
        
         protected override void OnStop()
        {
        
        WriteNetProfitToCSV();
        
        }
        

        private void ExecuteStrategy(TradeType tradeType)
        {
            CloseAllPositions();

            double volume = Symbol.QuantityToVolumeInUnits(LotSize);
            double atrPips = Math.Ceiling(atr.Result.Last(1) / Symbol.PipSize);

            if (tradeType == TradeType.Buy)
            {
                if (Strategy == StrategyType.Strategy1 || (Strategy == StrategyType.Strategy2 && Symbol.Ask > _fastMA.Result.LastValue && Symbol.Ask > _slowMA.Result.LastValue) || (Strategy == StrategyType.Strategy3 && _fastMA.Result.IsRising() && _slowMA.Result.IsRising()))
                {

                    PlaceOrder(tradeType, Symbol, volume, "Long", atrPips);
                }
            }
            else
            {
                if (Strategy == StrategyType.Strategy1 || (Strategy == StrategyType.Strategy2
                && Symbol.Bid < _fastMA.Result.LastValue && Symbol.Bid < _slowMA.Result.LastValue) || (Strategy == StrategyType.Strategy3
                && _fastMA.Result.IsFalling() && _slowMA.Result.IsFalling()))
                {

                    PlaceOrder(tradeType, Symbol, volume, "Short", atrPips);
                }
            }
        }
        private void PlaceOrder(TradeType tradeType, Symbol symbol, double volume, string label, double atrPips)
        {
            
            Print(atrPips);
            var stopLossPips = EnableStopLoss ? StopLoss*atrPips : 0;
            var takeProfitPips = EnableTakeProfit ? TakeProfit* atrPips : 0;

            var tradeResult = ExecuteMarketOrder(tradeType, symbol.Name, volume, label, stopLossPips, takeProfitPips);

            if (tradeResult.IsSuccessful && EnableTrailingStopLoss)
            {
                tradeResult.Position.ModifyTrailingStop(true);
            }
        }

        private void CloseAllPositions()
        {
            foreach (var position in Positions)
            {
                ClosePosition(position);
            }
        }
        
                public void WriteNetProfitToCSV()
        {
            // Calculate Net Profit
            double netProfit = History.Sum(trade => trade.NetProfit);

            // Define the CSV file path
            string csvFilePath = "C:\\N\\Net_Profits.csv";

            // Check if the CSV file exists
            if (!File.Exists(csvFilePath))
            {
                // If the file doesn't exist, create it and write the header
                using (StreamWriter sw = File.CreateText(csvFilePath))
                {
                    sw.WriteLine("Net Profit");
                }
            }

            // Write the Net Profit to the CSV file
            using (StreamWriter sw = File.AppendText(csvFilePath))
            {
                sw.WriteLine(netProfit.ToString());
            }

            Print("Net Profit written to CSV file.");
        }

        public enum StrategyType
        {
            Strategy1 = 1,
            Strategy2 = 2,
            Strategy3 = 3
        }

    }
}

 

 

 


@KJtech
Replies

firemyst
17 Jun 2023, 06:04

Your bot is closing all positions because you tell it to:

private void CloseAllPositions()
        {
            foreach (var position in Positions)
            {
                ClosePosition(position);
            }
        }

 

If you only want to close positions that your bot has specifically opened, then it's a two step process:

1) when you open a position, you need to assign a label to it (eg, "acBotPosition"), which is a string.

2) when looping through all the open positions, only close those positions whose label matches "acBotPosition":

private void CloseAllPositions()
        {
            foreach (var position in Positions)
            {
                if (position.Label == "acBotPosition")
                    ClosePosition(position);
            }
        }

 

 

As for the cut scenario, I wouldn't use the "HasCrossedAbove" method.

Instead, I would use logic similar to the following:

if (_fastMA.Result.Last(1) > _slowMA.Result.Last(1))
{
	ExecuteStrategy(TradeType.Buy);
}
else if (_fastMA.Result.Last(1) < _slowMA.Result.Last(1))
{
	ExecuteStrategy(TradeType.Sell);
}

 


@firemyst