Replies

oliver.r.m.92
20 Feb 2024, 19:19

RE: Amount to trade depending on stop loss

PanagiotisCharalampous said: 

Hi there,

Your calculation method does not make much sense to me. Here is the correct one

                        var maxAmountRisked = Account.Equity * (Risk / 100);                        return Symbol.NormalizeVolumeInUnits(maxAmountRisked / (StopLoss * Symbol.PipValue), RoundingMode.Down);

I have rewritten the code and used your part of code but now I have a new problem, in the log it shows this message: Crashed in OnBar with ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: volume. Actual value was: NaN.

The new code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MACDcBot : Robot
    {
        private bool isPositionOpen;
        private MacdCrossOver _MACD;
        private MovingAverage EMA;
        private const string label = "Trade ON";
        private double stopLossPrice;

        //MA                
        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("MA Type", Group = "Moving Average")]
        public MovingAverageType MAType { get; set; }

        [Parameter("MA Periods", Group = "Moving Average", DefaultValue = 200)]
        public int MAPeriods { get; set; }

        //MACD
        [Parameter("Period", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal-line crossover true:if Signal-line crossover false: Zero crossover", DefaultValue = true)]
        public bool IsSignalLineCrossover { get; set; }

        protected override void OnStart()
        {
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            EMA = Indicators.MovingAverage(SourceSeries, MAPeriods, MAType);
            isPositionOpen = false;
            Positions.Closed += OnPositionsClosed;
        }

        protected override void OnBar()
        {           
            if (Positions.Count > 0)
            {
                var position = Positions.LastOrDefault();

                if (position != null)
                {
                    if (position.TradeType == TradeType.Buy)
                        stopLossPrice = EMA.Result.LastValue - Symbol.PipSize * 2; // 2 pips por debajo de la SMA de 200
                    else if (position.TradeType == TradeType.Sell)
                        stopLossPrice = EMA.Result.LastValue + Symbol.PipSize * 2; // 2 pips por encima de la SMA de 200

                    double takeProfitPrice = position.EntryPrice + (position.EntryPrice - stopLossPrice) * 1.5;

                    ModifyPosition(position, stopLossPrice, takeProfitPrice);
                }
            }

            // Calcula el tamaño de posición basado en el riesgo
            var maxAmountRisked = Account.Equity * (1 / 100);
            var positionSize = Symbol.NormalizeVolumeInUnits(maxAmountRisked / (stopLossPrice * Symbol.PipValue), RoundingMode.Down);
            
            if (IsSignalLineCrossover)
            {
                if (!isPositionOpen && _MACD.Histogram.LastValue > 0 && _MACD.Signal.LastValue < 0 && _MACD.MACD.Last(3) < _MACD.Signal.Last(3) && _MACD.MACD.Last(2) > _MACD.Signal.Last(2) && Bars.HighPrices.Last(1) > EMA.Result.Last(3))
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, positionSize, label);
                    isPositionOpen = true;
                }

                if (!isPositionOpen && _MACD.Histogram.LastValue < 0 && _MACD.Signal.LastValue > 0 && _MACD.MACD.Last(3) > _MACD.Signal.Last(3) && _MACD.MACD.Last(2) < _MACD.Signal.Last(2) && Bars.LowPrices.Last(1) < EMA.Result.Last(3))
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, positionSize, label);
                    isPositionOpen = true;
                }
            }
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            isPositionOpen = false;
        }
    }
}

 


@oliver.r.m.92

oliver.r.m.92
20 Feb 2024, 07:52

RE: Amount to trade depending on stop loss

PanagiotisCharalampous said: 

Hi there, 

Please provide the code in proper format so that we can easily copy, paste and build it.

Best regards,

Panagiotis

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MACDcBot : Robot
    {
        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 0.12, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }

        // MA
        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("MA Type", Group = "Moving Average")]
        public MovingAverageType MAType { get; set; }

        [Parameter("MA Periods", Group = "Moving Average", DefaultValue = 200)]
        public int MAPeriods { get; set; }

        // MACD
        [Parameter("Period", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal-line crossover true:if Signal-line crossover false: Zero crossover", DefaultValue = true)]
        public bool IsSignalLineCrossover { get; set; }

        private bool isPositionOpen;
        private MacdCrossOver _MACD;
        private MovingAverage EMA;
        private const string label = "Trade ON";

        private double VolumeInUnits
        {
            get { return Symbol.NormalizeVolumeInUnits(Symbol.QuantityToVolumeInUnits(Quantity)); }
        }

        protected override void OnStart()
        {
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            EMA = Indicators.MovingAverage(SourceSeries, MAPeriods, MAType);
            isPositionOpen = false;
            Positions.Closed += OnPositionsClosed;
        }

        protected override void OnTick()
        {
            // Verifica si hay posiciones abiertas
            if (Positions.Count == 0)
                return;

            // Obtén la última posición abierta
            var position = Positions.LastOrDefault();

            // Calcula el stop loss basado en la posición abierta
            double stopLossPrice;

            if (position.TradeType == TradeType.Buy)
                stopLossPrice = EMA.Result.LastValue - Symbol.PipSize * 2; // 2 pips por debajo de la SMA de 200
            else if (position.TradeType == TradeType.Sell)
                stopLossPrice = EMA.Result.LastValue + Symbol.PipSize * 2; // 2 pips por encima de la SMA de 200           
            else
                return; // No es necesario establecer el stop loss para otras operaciones

            // Calcula el take profit como 1.5 veces el stop loss
            double takeProfitPrice = position.EntryPrice + (position.EntryPrice - stopLossPrice) * 1.5;

            // Establece el stop loss y take profit
            ModifyPosition(position, stopLossPrice, takeProfitPrice);
        }

        protected override void OnBar()
        {
            if (IsSignalLineCrossover)
            {

                if (!isPositionOpen && _MACD.Histogram.Last(1) > (0) && _MACD.MACD.Last(2) < _MACD.Signal.Last(2) && _MACD.MACD.Last(1) > _MACD.Signal.Last(1) && Bars.HighPrices.Last(1) > EMA.Result.Last(2))
                {
                    double stopLossPrice = EMA.Result.LastValue - Symbol.PipSize * 2; // 2 pips por debajo de la SMA de 200
                    double takeProfitPrice = Bars.HighPrices.Last(1) + Symbol.PipSize * 2; // 2 pips por encima del máximo previo
                    double lotSize = CalculateLotSize(stopLossPrice);
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, lotSize, label);
                    isPositionOpen = true;
                }

                if (!isPositionOpen && _MACD.Histogram.Last(1) < (0) && _MACD.MACD.Last(2) > _MACD.Signal.Last(2) && _MACD.MACD.Last(1) < _MACD.Signal.Last(1) && Bars.LowPrices.Last(1) < EMA.Result.Last(2))
                {
                    double stopLossPrice = EMA.Result.LastValue + Symbol.PipSize * 2; // 2 pips por encima de la SMA de 200
                    double takeProfitPrice = Bars.LowPrices.Last(1) - Symbol.PipSize * 2; // 2 pips por debajo del mínimo previo
                    double lotSize = CalculateLotSize(stopLossPrice);
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, lotSize, label);
                    isPositionOpen = true;
                }
            }
        }

        private double CalculateLotSize(double stopLossPrice)
        {
            double accountBalance = Account.Balance;
            double riskAmount = accountBalance * 0.01; // 1% del balance
            double distanceToStopLoss = Math.Abs(stopLossPrice - Bars.ClosePrices.LastValue); // Distancia al stop loss
            double valuePerPip = Symbol.PipValue * Symbol.QuantityToVolumeInUnits(1); // Valor por pip
            double lotSize = riskAmount / (distanceToStopLoss * valuePerPip); // Lotaje calculado
            return lotSize;
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            // Actualizar el estado de la posición abierta
            isPositionOpen = false;
        }
    }
}


@oliver.r.m.92

oliver.r.m.92
13 Feb 2024, 14:24

RE: Backtesting indexes don´t show results

PanagiotisCharalampous said: 

Hi Oliver,

Check your log and you will discover the reason. You need to normalize the volume as below

        private double VolumeInUnits        {            get { return Symbol.NormalizeVolumeInUnits(Symbol.QuantityToVolumeInUnits(Quantity)); }        }

Best regards,

Panagiotis

Perfect, thak you! That was the error, is the code you have provided me the one that should always be used, whether indexes, forex or anything that is operated? The one that was already in my code works only with forex, is it equally correct or have I been using it wrong?

 


@oliver.r.m.92

oliver.r.m.92
12 Feb 2024, 17:19 ( Updated at: 13 Feb 2024, 06:51 )

RE: Backtesting indexes don´t show results

PanagiotisCharalampous said: 

Hi there,

There is probably an issue with your cBot's logic. Please share your cBot code, your broker and the backtesting parameters so that we can reproduce and advise accordingly.

Best regards,

Panagiotis

Hi Panagiotis! The broker im using its ICMarkets, the parameters wich I tryed to test the Cbot on US500 are the shame on the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class MACDcBot : Robot
    {
                 
        [Parameter("Quantity (Lots)", Group = "Volume", DefaultValue = 0.12, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }
        
        //SL & TP
        [Parameter("Stop Loss (pips)", Group = "Protection", DefaultValue = 50)]
        public int StopLossInPips { get; set; }

        [Parameter("Take Profit (pips)", Group = "Protection", DefaultValue = 30)]
        public int TakeProfitInPips { get; set; }
        
        //MA               
        [Parameter("Source", Group = "Moving Average")]
        public DataSeries SourceSeries { get; set; }
        
        [Parameter("MA Type", Group = "Moving Average")]
        public MovingAverageType MAType { get; set; }
        
        [Parameter("MA Periods", Group = "Moving Average", DefaultValue = 200)]
        public int MAPeriods { get; set; }
        
        //MACD
        [Parameter("Period", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Signal-line crossover true:if Signal-line crossover false: Zero crossover", DefaultValue = true)]
        public bool IsSignalLineCrossover { get; set; }
        
        private bool isPositionOpen;
        private MacdCrossOver _MACD;
        private MovingAverage SMA;
        private const string label = "Trade ON";
        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            // Actualizar el estado de la posición abierta
            isPositionOpen = false;                 
        }
        private double VolumeInUnits
        {
            get { return Symbol.QuantityToVolumeInUnits(Quantity); }
        }
        
        protected override void OnStart()
        {
            _MACD = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            SMA = Indicators.MovingAverage(SourceSeries, MAPeriods, MAType);
            isPositionOpen = false;
            Positions.Closed += OnPositionsClosed;
        }

        protected override void OnBar()
        {           
            if (IsSignalLineCrossover)
            {


                if (!isPositionOpen && _MACD.Histogram.Last(1) > (0) && _MACD.MACD.Last(2) < _MACD.Signal.Last(2) && _MACD.MACD.Last(1) > _MACD.Signal.Last(1) && Bars.HighPrices.Last(1) > SMA.Result.Last(2))
                {                 
                   ExecuteMarketOrder(TradeType.Buy, SymbolName, VolumeInUnits, label,StopLossInPips, TakeProfitInPips);
                   isPositionOpen = true;
                }
                
                if (!isPositionOpen && _MACD.Histogram.Last(1) < (0) && _MACD.MACD.Last(2) > _MACD.Signal.Last(2) && _MACD.MACD.Last(1) < _MACD.Signal.Last(1) && Bars.LowPrices.Last(1) < SMA.Result.Last(2))
                {               
                   ExecuteMarketOrder(TradeType.Sell, SymbolName, VolumeInUnits, label, StopLossInPips, TakeProfitInPips);
                   isPositionOpen = true;                                                            
                }
            }
            //Zero cross over
            else
            {
                if (!isPositionOpen && _MACD.MACD.Last(1) > 0 && _MACD.MACD.Last(2) < 0)
                {
                    //up
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, VolumeInUnits, label,StopLossInPips, TakeProfitInPips);
                    isPositionOpen = true;
                }
                else if (!isPositionOpen && _MACD.MACD.Last(1) < 0 && _MACD.MACD.Last(2) > 0)
                {
                    //Down
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, VolumeInUnits, label,StopLossInPips, TakeProfitInPips);  
                    isPositionOpen = true;
                }
                
            }  
        }
    }
}

 


@oliver.r.m.92