Having trouble opening trades with defined risk

Created at 17 Sep 2017, 01:10
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!
DA

danblackadder

Joined 17.09.2017

Having trouble opening trades with defined risk
17 Sep 2017, 01:10


Hi,

I have written a small piece of code, which it seems the cAlgo platform is having trouble with.

[Parameter("Risk", DefaultValue = 0.01, MinValue = 0.01, MaxValue = 100, Step = 0.01)] 
public double riskPercentage { get; set; }
private void Open(TradeType tradeType)
{
//define the volume to trade (risk*account balance) * leverage
var volumeToTrade = (riskPercentage * Account.Balance) * Symbol.PreciseLeverage;
 //Convert.ToInt64 required to convert double to long for volume type.
ExecuteMarketOrder(tradeType, Symbol, Convert.ToInt64(Volume), "Position");

}

 

Effectively, if I have £10,000 account balance, the the symbol leverage is 100, the calculation with a 0.01 risk would be:

(0.01*10000)*100 = 10000 unit size. 

The system effectively dies very quickly, only opening a small number of trades early on. I have used the minute time frame over a month period, where effectively there should be a large number of options for trades to open, and it still dies very quickly.

If I change to the traditional usage of settings a volume directly in the code. I do not have an issue. 

The reason I want to define the risk, is becuase effectively I want to increase the volume traded as my balance gets higher during optimisation.

Am I doing something wrong? Or is the system not designed with this in mind?

Thanks in advance,

Dan


@danblackadder
Replies

Spotware
18 Sep 2017, 10:58

Dear Trader,

Thanks for posting your question in our forum. The provided code sample does not provide all the necessary information for someone to help you. For example, where is volumeToTrade used? Where is the Volume parameter defined? It would be easier for somebody to help you if you provide the code for the cBot, so that someone can reproduce the described behavior.

Best Regards,

cTrader Team


@Spotware

danblackadder
18 Sep 2017, 23:48

Hi,

Thanks for your reply.

Apologies, it probably doesn't make sense because I was using 2 seperate variables, when they should have been 1 and the same. I had to change the code since due to the errors that were occuring.

 

My code also uses a custom indicators, so I have copied it over to a basic cBot for you.

In the below, if you leave it in its current state, it will make 1 trade. If you change the volume to a set figure, it will work as intended.

// -------------------------------------------------------------------------------------------------
//
//    This code is a cAlgo API sample.
//
//    This cBot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk.
//
//    The "Sample Trend cBot" will buy when fast period moving average crosses the slow period moving average and sell when 
//    the fast period moving average crosses the slow period moving average. The orders are closed when an opposite signal 
//    is generated. There can only by one Buy or Sell order at any time.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SampleTrendcBot : Robot
    {
        [Parameter("MA Type")]
        public MovingAverageType MAType { get; set; }

        [Parameter()]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Slow Periods", DefaultValue = 10)]
        public int SlowPeriods { get; set; }

        [Parameter("Fast Periods", DefaultValue = 5)]
        public int FastPeriods { get; set; }

        [Parameter("Risk", DefaultValue = 0.01, MinValue = 0.01, MaxValue = 100, Step = 0.01)]
        public double risk { get; set; }

        private MovingAverage slowMa;
        private MovingAverage fastMa;
        private const string label = "Position";

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriods, MAType);
            slowMa = Indicators.MovingAverage(SourceSeries, SlowPeriods, MAType);
        }

        protected override void OnTick()
        {
            var longPosition = Positions.Find(label, Symbol, TradeType.Buy);
            var shortPosition = Positions.Find(label, Symbol, TradeType.Sell);

            var currentSlowMa = slowMa.Result.Last(0);
            var currentFastMa = fastMa.Result.Last(0);
            var previousSlowMa = slowMa.Result.Last(1);
            var previousFastMa = fastMa.Result.Last(1);

            if (previousSlowMa > previousFastMa && currentSlowMa <= currentFastMa && longPosition == null)
            {


                if (shortPosition != null)
                {

                    Close(TradeType.Sell);

                }

                Open(TradeType.Buy);

            }
            else if (previousSlowMa < previousFastMa && currentSlowMa >= currentFastMa && shortPosition == null)
            {

                if (longPosition != null)
                {

                    Close(TradeType.Buy);

                }

                Open(TradeType.Sell);

            }

        }

        private void Close(TradeType tradeType)
        {

            foreach (var position in Positions.FindAll(label, Symbol, tradeType))
                ClosePosition(position);

        }

        private void Open(TradeType tradeType)
        {

            var volumeToTrade = (risk * Account.Balance) * Symbol.PreciseLeverage;
            //var volumeToTrade = 1000;

            if (volumeToTrade > Symbol.VolumeMin)
            {

                ExecuteMarketOrder(tradeType, Symbol, Convert.ToInt64(volumeToTrade), label);

            }
            else
            {

                ExecuteMarketOrder(tradeType, Symbol, Symbol.VolumeMin, label);

            }

        }
    }
}

Thank you for you time.


@danblackadder

Spotware
19 Sep 2017, 09:04

Dear Trader,

If you add a Print() function and try to print volumeToTrade in the log, then you will notice that the volume you are trying to trade (9997.65) does not comply to the  Symbol.VolumeStep setting. The volume used should always be divisible with the Symbol.VolumeStep value.

            var volumeToTrade = (risk * Account.Balance) * Symbol.PreciseLeverage;
            //var volumeToTrade = 1000;
            Print(volumeToTrade);

Best Regards,

cTrader Team


@Spotware

danblackadder
19 Sep 2017, 11:34

Hi,

Okay, that makes sense. So I should just be able to round to a number divisible with the Symbol.VolumeStep.

I will try to fix this tonight and report back if I have done incase anyone else wants to use the same script.

Thanks!

Dan


@danblackadder

danblackadder
20 Sep 2017, 00:37

Incase anyone else wants to use this in their own way, I found a fix:

            var volumeAvailable = (riskPercentage * Account.Balance) * Symbol.PreciseLeverage;

            var volumeToTrade = volumeAvailable % 1000 >= 500 ? volumeAvailable + 1000 - volumeAvailable % 1000 : volumeAvailable - volumeAvailable % 1000;

            if (volumeToTrade > Symbol.VolumeMin)
            {

                ExecuteMarketOrder(tradeType, Symbol, Convert.ToInt64(volumeToTrade), "Position", Symbol.Spread, null);

            }
            else
            {

                ExecuteMarketOrder(tradeType, Symbol, Symbol.VolumeMin, "Position");

            }

By checking if the current volumeAvailable modulo is bigger than 500, it will round up, and if it isn't it will round down. The rounding is complete by adding the difference between 1000 and the remainder, or simply removing the remainder. 

 

In a bot (the Risk reference is set to 0.01 for 1% 0.05 for 5% 0.10 for 10% or 1 for 100%, meaning you would be willing to risk 100% of your capital to open 1 single trade. If you only risk 0.01 (1%) then you are able to open 100 trades before you run out of capital.

// -------------------------------------------------------------------------------------------------
//
//    This code is a cAlgo API sample.
//
//    This cBot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk.
//
//    The "Sample Trend cBot" will buy when fast period moving average crosses the slow period moving average and sell when 
//    the fast period moving average crosses the slow period moving average. The orders are closed when an opposite signal 
//    is generated. There can only by one Buy or Sell order at any time.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SampleTrendcBot : Robot
    {
        [Parameter("MA Type")]
        public MovingAverageType MAType { get; set; }

        [Parameter()]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Slow Periods", DefaultValue = 10)]
        public int SlowPeriods { get; set; }

        [Parameter("Fast Periods", DefaultValue = 5)]
        public int FastPeriods { get; set; }

        [Parameter("Risk", DefaultValue = 0.01, MinValue = 0.01, MaxValue = 1, Step = 0.01)]
        public double risk { get; set; }

        private MovingAverage slowMa;
        private MovingAverage fastMa;
        private const string label = "Position";

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriods, MAType);
            slowMa = Indicators.MovingAverage(SourceSeries, SlowPeriods, MAType);
        }

        protected override void OnTick()
        {
            var longPosition = Positions.Find(label, Symbol, TradeType.Buy);
            var shortPosition = Positions.Find(label, Symbol, TradeType.Sell);

            var currentSlowMa = slowMa.Result.Last(0);
            var currentFastMa = fastMa.Result.Last(0);
            var previousSlowMa = slowMa.Result.Last(1);
            var previousFastMa = fastMa.Result.Last(1);

            if (previousSlowMa > previousFastMa && currentSlowMa <= currentFastMa && longPosition == null)
            {


                if (shortPosition != null)
                {

                    Close(TradeType.Sell);

                }

                Open(TradeType.Buy);

            }
            else if (previousSlowMa < previousFastMa && currentSlowMa >= currentFastMa && shortPosition == null)
            {

                if (longPosition != null)
                {

                    Close(TradeType.Buy);

                }

                Open(TradeType.Sell);

            }

        }

        private void Close(TradeType tradeType)
        {

            foreach (var position in Positions.FindAll(label, Symbol, tradeType))
                ClosePosition(position);

        }

        private void Open(TradeType tradeType)
        {

            var volumeAvailable = (riskPercentage * Account.Balance) * Symbol.PreciseLeverage;

            var volumeToTrade = volumeAvailable % 1000 >= 500 ? volumeAvailable + 1000 - volumeAvailable % 1000 : volumeAvailable - volumeAvailable % 1000;

            if (volumeToTrade > Symbol.VolumeMin)
            {

                ExecuteMarketOrder(tradeType, Symbol, Convert.ToInt64(volumeToTrade), "Position", Symbol.Spread, null);

            }
            else
            {

                ExecuteMarketOrder(tradeType, Symbol, Symbol.VolumeMin, "Position");

            }

        }
    }
}

 


@danblackadder