Calculating Volume

Created at 23 Sep 2013, 11:39
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!
virtuesoft's avatar

virtuesoft

Joined 21.06.2013

Calculating Volume
23 Sep 2013, 11:39


I have created some code to calculate the exact volume to trade, based on the risk percent and the size of the stop loss. Here is the code and some notes...

Firstly, I added four new parameters to my robot. These are pretty self explanatory...

        [Parameter("Risk Percent", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 55000)]
        public int ReserveFunds { get; set; }

        [Parameter("Commission (Each Way)", DefaultValue = 27)]
        public double Commission { get; set; }

        [Parameter("Max Volume", DefaultValue = 2000000)]
        public int MaxVolume { get; set; }

The "Reserve Funds" parameter is the only parameter that may require some further explanation. Most of us don't keep all our funds in our trading account. We only keep enough to cover margins plus a little extra. The Reserve Funds parameter allows us to specify how much of our funds are outside of our trading account. The code adds the Reserve Funds value to the account balance and uses that to calculate the risk. 

All of the work is down in two functions. The main function is called CalculateVolume, and the other is called CalculateCommission, which is called from within the CalculateVolume function. Here are the functions...

        private int CalculateVolume(double stopLoss)
        {
            Print("Calculating Volume - Symbol: {0}, Risk: {1}, Commission (each way per Million): {2}, Stop Loss: {3}", Symbol.Code, RiskPercent, Commission, stopLoss);

            int volume = 10000;

            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed in GBP per trade.
            double riskGbp = (totalBalance * RiskPercent) / 100;

            // Remove the first 3 characters. We're not interested in the base currency. We only care about the quote currency.
            string quoteCcy = Symbol.Code.Remove(0, 3);

            // Calculate the spread and the commission cost per 100k for the current symbol.
            double spread = Math.Round((Symbol.Ask - Symbol.Bid) / Symbol.PipSize, 1);
            double commissionCostPer100k = CalculateCommissionPer100k();
            double costPerPip100k = double.NaN;

            Print("Calculating Volume - Symbol: {0}, Risk: {1}, Stop Loss: {2}, Total Balance: {3}, Risk Per Trade (GBP): {4}, Spread: {5}", Symbol.Code, RiskPercent, stopLoss, totalBalance, riskGbp, spread);

            // Calculate the cost per pip value. This will be different depending on the quoute currency.
            if (quoteCcy == "USD")
            {
                // Pairs ending in USD always have a pip value of $10 per 100k. Use GBPUSD to convert this to GBP. 
                costPerPip100k = 10 / MarketData.GetSymbol("GBPUSD").Bid;
            }
            else if (quoteCcy == "JPY")
            {
                // Pairs ending in JPY always have a pip value of ¥‎1000 per 100k. Use GBPJPY to convert this to GBP. 
                costPerPip100k = 1000 / MarketData.GetSymbol("GBPJPY").Bid;
            }
            else if (quoteCcy == "GBP")
            {
                // Pairs ending in GBP always have a pip value of £‎10 per 100k. Since this is the same as the account currency we do not need to perform a conversion.  
                costPerPip100k = 10;
            }
            else if (quoteCcy == "CHF")
            {
                // Pairs ending in CHF always have a pip value of 10CHF per 100k. Use GBPCHF to convert this to GBP. 
                costPerPip100k = 10 / MarketData.GetSymbol("GBPCHF").Bid;
            }
            else if (quoteCcy == "AUD")
            {
                // Pairs ending in AUD always have a pip value of 10AUD per 100k. Use GBPAUD to convert this to GBP. 
                costPerPip100k = 10 / MarketData.GetSymbol("GBPAUD").Bid;
            }
            else if (quoteCcy == "CAD")
            {
                // Pairs ending in CAD always have a pip value of 10CAD per 100k. Use GBPCAD to convert this to GBP. 
                costPerPip100k = 10 / MarketData.GetSymbol("GBPCAD").Bid;
            }
            else if (quoteCcy == "NZD")
            {
                // Pairs ending in NZD always have a pip value of 10NZD per 100k. Use GBPNZD to convert this to GBP. 
                costPerPip100k = 10 / MarketData.GetSymbol("GBPNZD").Bid;
            }

            // Only continue if the cost per pip has been calculated.
            if (!double.IsNaN(costPerPip100k))
            {
                // Calculate the cost of the spread
                double spreadCostPer100k = costPerPip100k * spread;

                // Add the commission and spread costs to come up with the total cost per 100k for this trade.
                double totalCostPer100k = spreadCostPer100k + commissionCostPer100k;

                // Calculate the exact volume to be traded. Then round the volume to the nearest 10,000 and convert to an int so that it can be returned to the caller.
                double exactVolume = (riskGbp / ((costPerPip100k * stopLoss) + totalCostPer100k)) * 100000;
                volume = (((int)exactVolume) / 10000) * 10000;

                Print("Exact Volume: {0}, Rounded Volume: {1}, Cost Per Pip per 100k: {2}, Spread Cost per 100k: {3}, Total Cost per 100k: {4}", exactVolume, volume, costPerPip100k, spreadCostPer100k, totalCostPer100k);
            }

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (volume > MaxVolume)
                volume = MaxVolume;

            return volume;
        }

        private double CalculateCommissionPer100k()
        {
            double commissionGBP = 0;
            string baseCcy = Symbol.Code.Remove(3, 3);

            // The Commission parameter is the cost each way per million. Calculate the full commission (in and out) per 100k of the base currency.
            double baseCcyCommission = (Commission * 2) / 10;

            if (baseCcy == "EUR")
            {
                // Use EURGBP to convert the EUR commission value to GBP.            
                commissionGBP = baseCcyCommission * MarketData.GetSymbol("EURGBP").Bid;
            }
            else if (baseCcy == "USD")
            {
                // Use GBPUSD to convert the USD commission value to GBP.            
                commissionGBP = baseCcyCommission / MarketData.GetSymbol("GBPUSD").Bid;
            }
            else if (baseCcy == "GBP")
            {
                // The base currency is the same as the account currency. No conversion required.
                commissionGBP = baseCcyCommission;
            }
            else if (baseCcy == "CHF")
            {
                // Use GBPCHF to convert the CHF commission value to GBP.            
                commissionGBP = baseCcyCommission / MarketData.GetSymbol("GBPCHF").Bid;
            }
            else if (baseCcy == "AUD")
            {
                // Use GBPAUD to convert the AUD commission value to GBP.            
                commissionGBP = baseCcyCommission / MarketData.GetSymbol("GBPAUD").Bid;
            }
            else if (baseCcy == "CAD")
            {
                // Use GBPCAD to convert the CAD commission value to GBP.            
                commissionGBP = baseCcyCommission / MarketData.GetSymbol("GBPCAD").Bid;
            }
            else if (baseCcy == "NZD")
            {
                // Use GBPNZD to convert the NZD commission value to GBP.            
                commissionGBP = baseCcyCommission / MarketData.GetSymbol("GBPNZD").Bid;
            }

            return commissionGBP;
        }

To calculate the volume from within your robot, simply use the following code...

// Where StopLossSize is equal to the size of the stop loss for your trade.
CalculateVolume(StopLossSize)

All of the code above converts to a GBP account. However, it would be pretty simple to change the code to convert to a EUR or USD based account. You would just have to use different symbols to perform the conversion (e.g. swap GBPJPY for EURJPY or USDJPY). If anyone has any interest in this code but wants to see it in a EUR or USD account let me know and I'll recode it and add it to this thread. 

Also, if anyone can see any errors or knows of a better way to do this please let me know.

Thanks.


@virtuesoft
Replies

chiller
28 Jan 2014, 21:12

Hello,

could you please convert your great code for a EUR-Account.

Thank you so much! 

 

regards

Chiller


@chiller

cvphuoc
29 Jan 2014, 04:48

RE:

Hi virtuesoft,

Could you please also modify this for USD-based account.

Many thanks in advance.

Cvphuoc


@cvphuoc

virtuesoft
29 Jan 2014, 11:22

RE: RE:

Hi,

I no longer use the code above. It is a lot easier to calculate the volume now that Symbol.PipSize has been added to the API.

Here is the code I am now using...

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }

 


@virtuesoft

virtuesoft
29 Jan 2014, 11:28

Please note that there are a number of different parameters that I use in the code above. I think they're pretty self explanatory but let me know if you have any queries.

        ("Stop Loss", DefaultValue = 6.0)]
        public double StopLoss { get; set; }

        [Parameter("Commission in Pips", DefaultValue = 0.8)]
        public double CommissionPips { get; set; }

        [Parameter("Risk Percent", DefaultValue = 0.5, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 0)]
        public int ReserveFunds { get; set; }

        [Parameter("Max Volume", DefaultValue = 5000000)]
        public int MaxVolume { get; set; }

This code should work on all accounts (GBP, EUR, USD etc), however, I've only tested it on a GBP account.

Also, if you want to round the volume down to the nearest 10,000, instead of 100,000 just take a 0 off the two numbers on line 14 in post #4.


@virtuesoft

virtuesoft
29 Jan 2014, 11:31

RE: RE: RE:

virtuesoft said:

Hi,

I no longer use the code above. It is a lot easier to calculate the volume now that Symbol.PipSize has been added to the API.

Here is the code I am now using...

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }

 

Sorry, in this post I meant to say that it's a lot easier to calculate volume now that Symbol.PipValue has been introduced, not Symbol.PipSize.

Apologies for the confusion and layout of these posts. I'm at work at the moment and I'm quite busy.


@virtuesoft

chiller
29 Jan 2014, 12:02

No problem.

All works fine!

Thanks again.


@chiller

cvphuoc
30 Jan 2014, 04:55

Hi virtuesoft & chiller,

Thank all of you for this valuble topic. Badly i'm a newbie with Ctrader and don't know how to assemble these into full indicators/cbots. Could you pls kindly give full code for volume calculation? Sorry for my disturbance.

Regards.

CVPhuoc


@cvphuoc

virtuesoft
30 Jan 2014, 10:14

RE:

cvphuoc, here is an example of how you can use the code...

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class ExampleRobot : Robot
    {
        [Parameter("Stop Loss", DefaultValue = 6.0)]
        public double StopLoss { get; set; }

        [Parameter("Commission in Pips", DefaultValue = 0.8)]
        public double CommissionPips { get; set; }

        [Parameter("Risk Percent", DefaultValue = 0.5, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 0)]
        public int ReserveFunds { get; set; }

        [Parameter("Max Volume", DefaultValue = 5000000)]
        public int MaxVolume { get; set; }

        private int _volume;

        protected override void OnStart()
        {
            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnBar()
        {
            CalculateVolume();
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }
    }
}

 


@virtuesoft

Spotware
30 Jan 2014, 10:31

See also: NormalizeVolume. You can use it to round up, down or to the nearest volume accepted for trade.


@Spotware

virtuesoft
30 Jan 2014, 10:35

RE:

Spotware said:

See also: NormalizeVolume. You can use it to round up, down or to the nearest volume accepted for trade.

 

Thanks. I didn't know that function existed.


@virtuesoft

kdcp999
11 Feb 2017, 23:20

why include commission in volume

Hello, Thanks for this btw.

I may be misunderstanding something here:

 

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;


But why include commission in you volume to trade. You are going to be charged that commission anyways. So if you make a winning trade you cover the commission loss along with the profits.

But if you lose then you still pay the commission for entering and exiting along with the added value you lose for including the commission rati into your volume level.

Could you please clarify - I appreciate that this is a very old post. Any advice would be great thanks.


@kdcp999

kricka
12 Feb 2017, 18:24

The reason to include the commission is you can then calculate the correct risk management for the trade. 


@kricka

firemyst
19 Apr 2019, 07:59

RE: RE: RE:

virtuesoft said:

Hi,

I no longer use the code above. It is a lot easier to calculate the volume now that Symbol.PipSize has been added to the API.

Here is the code I am now using...

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }

 

 

I believe lines 13 onwards in post #5 should now be changed to:

double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);

//Choose your own rounding mode
exactVolume = (int)Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down);

// Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
if (exactVolume > MaxVolume)
    exactVolume = MaxVolume;

 


@firemyst

Tj11
02 Apr 2020, 14:02

small add to make units right :

.

            //entry in cash
            double riskPerTrade = (Account.Balance * EntryPercentage) / 100;
            //pips
            double stop = StopLoss * Math.Pow(10, Symbol.Digits - 1);
            double comission = Commission / 10;
            double spread = Symbol.Spread * Math.Pow(10, Symbol.Digits - 1);
            double totalPips = stop + comission + spread;

            //exact volume to trade
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            //round volume to 0.01 lot
            int volume = (((int)exactVolume) / 1000) * 1000;
            //make sure min volume used
            volume = (volume < 1000) ? 1000 : volume;


@Tj11

Tj11
09 Apr 2020, 14:56

Last version from me :

.

public int getVolume(double StopLoss, bool upper)
        {
            //entry in cash
            double riskPerTrade = (Account.Balance * EntryPercentage) / 100;
            //pips
            double stop = (Symbol.PipSize == Symbol.TickSize) ? StopLoss * Math.Pow(10, Symbol.Digits) : StopLoss * Math.Pow(10, Symbol.Digits - 1);
            double commission = Commission / 10;
            double spread = (Symbol.PipSize == Symbol.TickSize) ? Symbol.Spread * Math.Pow(10, Symbol.Digits) : Symbol.Spread * Math.Pow(10, Symbol.Digits - 1);
            double totalPips = stop + spread;
            //Print("totalPips ", totalPips, "   stop ", stop, "   commission ", commission, "   upper ", upper, "   spread ", spread);


            //exact volume to trade
            double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);

            //account for comission properly
            int count = 0;
            double diff = 1;
            double corrdVolume = exactVolume;
            while (diff > 0.01 && count < 10)
            {
                //comission in cash
                double _commission = (Symbol.Name == "XTIUSD" || Symbol.Name == "XBRUSD") ? Commission / 50 : Commission;
                double cashComm = corrdVolume * _commission / Symbol.LotSize;
                double cashStop = corrdVolume * Symbol.PipValue * totalPips;
                double loss = cashStop + cashComm;
                //Print("loss ", Math.Round(loss), "   cashStop ", Math.Round(cashStop), "   cashComm ", Math.Round(cashComm, 2));
                diff = Math.Abs(loss / riskPerTrade - 1);

                //correction
                if (diff > 0.01)
                {
                    double diffCash = riskPerTrade - loss;
                    double diffVolume = diffCash / (Symbol.PipValue * (totalPips + commission));
                    corrdVolume = corrdVolume + diffVolume;
                    //Print("Interm corrdVolume ", Math.Round(corrdVolume), "    diffVolume ", Math.Round(diffVolume), "   exactVolume ", Math.Round(exactVolume), "   diffCash ", Math.Round(diffCash), "   diff ", Math.Round(diff, 3), "   count ", count, "   loss ", Math.Round(loss), "   riskPerTrade ", Math.Round(riskPerTrade));
                }
                else
                {
                    //Print("Final corrdVolume ", Math.Round(corrdVolume), "   exactVolume ", Math.Round(exactVolume), "   diff ", Math.Round(diff, 3), "   count ", count, "   loss ", Math.Round(loss), "   riskPerTrade ", Math.Round(riskPerTrade));
                }

                count++;
            }

            //normalize the volume
            double normVolume = Symbol.NormalizeVolumeInUnits(corrdVolume, RoundingMode.ToNearest);
            //make sure volume within accepted range
            double accVolume = (normVolume < Symbol.VolumeInUnitsMin) ? Symbol.VolumeInUnitsMin : (normVolume > Symbol.VolumeInUnitsMax) ? Symbol.VolumeInUnitsMax : normVolume;
            //get volume
            int volume = (int)accVolume;
            //Symbol.QuantityToVolumeInUnits(lot);
            //Print("LotSize ", Symbol.LotSize, "   PipSize ", Symbol.PipSize, "   PipValue ", Symbol.PipValue, "   TickSize ", Symbol.TickSize, "   TickValue ", Symbol.TickValue, "   VolumeInUnitsStep ", Symbol.VolumeInUnitsStep);
            //Print("volume ", volume, "   accVolume ", accVolume, "   normVolume ", normVolume, "   exactVolume ", exactVolume, "   riskPerTrade ", riskPerTrade, "   totalPips ", totalPips, "   stop ", stop, "   comission ", commission, "   spread ", spread, "   Symbol.LotSize ", Symbol.LotSize);

            return volume;
            //source  :  https://ctrader.com/forum/cbot-support/1573?page=1
        }

.

cheers

 


@Tj11

prosteel1
27 Jun 2020, 08:34

RE: RE:

virtuesoft said:

cvphuoc, here is an example of how you can use the code...

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class ExampleRobot : Robot
    {
        [Parameter("Stop Loss", DefaultValue = 6.0)]
        public double StopLoss { get; set; }

        [Parameter("Commission in Pips", DefaultValue = 0.8)]
        public double CommissionPips { get; set; }

        [Parameter("Risk Percent", DefaultValue = 0.5, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 0)]
        public int ReserveFunds { get; set; }

        [Parameter("Max Volume", DefaultValue = 5000000)]
        public int MaxVolume { get; set; }

        private int _volume;

        protected override void OnStart()
        {
            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnBar()
        {
            CalculateVolume();
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        private void CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = StopLoss + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded. Then round the volume to the nearest 100,000 and convert to an int so that it can be returned to the caller.
            double exactVolume = Math.Round(riskPerTrade / (Symbol.PipValue * totalPips), 2);
            _volume = (((int)exactVolume) / 100000) * 100000;

            // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
            if (_volume > MaxVolume)
                _volume = MaxVolume;
        }
    }
}

 

Thanks for this @virtuesoft, I have found the Symbol.NormalizeVolumeInUnits will round to the lowest volume even if the exactVolume is smaller than the Symbol.VolumeInUnitsMin.

So I have added an extra check to return -1 which I then check for in the place order code. This prevents a trade of the minimum trade size if it would result in more than the allowed risk being used. An example of this is on a small account trading 50 barrels of XBRUSD when 1% risk is only 5 barrels.

private double CalculateVolume(double SL)
{
    // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
    double totalBalance = Account.Balance + ReserveFunds;

    // Calculate the total risk allowed per trade.
    double riskPerTrade = (totalBalance * RiskPercent) / 100;

    // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
    double totalPips = (SL / Symbol.PipSize) + ComissionPips + Symbol.Spread;

    // Calculate the exact volume to be traded.
    double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);
    if (exactVolume >= Symbol.VolumeInUnitsMin)
    {
        _volume = Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down);

        // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
        if (_volume > MaxVolume)
            _volume = MaxVolume;
    }
    else
    {
        _volume = -1;
        Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
    }
    return _volume;
}

 


@prosteel1

Alwin123
30 Oct 2022, 20:05

what did i wrong i have 3 errors in this script?

using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Requests;
using cAlgo.Indicators;

namespace cAlgo.Robots
{
    [Robot()]
    public class ExampleRobot : Robot
    {
        [Parameter("Stop Loss", DefaultValue = 6.0)]
        public double StopLoss { get; set; }

        [Parameter("Commission in Pips", DefaultValue = 0.8)]
        public double CommissionPips { get; set; }

        [Parameter("Risk Percent", DefaultValue = 0.5, MinValue = 0.1, MaxValue = 5.0)]
        public double RiskPercent { get; set; }

        [Parameter("Reserve Funds", DefaultValue = 0)]
        public int ReserveFunds { get; set; }

        [Parameter("Max Volume", DefaultValue = 5000000)]
        public int MaxVolume { get; set; }

        private int _volume;

        protected override void OnStart()
        {
            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnBar()
        {
            CalculateVolume();
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }

        private double CalculateVolume()
        {
            // Our total balance is our account balance plus any reserve funds. We do not always keep all our money in the trading account. 
            double totalBalance = Account.Balance + ReserveFunds;

            // Calculate the total risk allowed per trade.
            double riskPerTrade = (totalBalance * RiskPercent) / 100;

            // Add the stop loss, commission pips and spread to get the total pips used for the volume calculation.
            double totalPips = (StopLoss / Symbol.PipSize) + CommissionPips + Symbol.Spread;

            // Calculate the exact volume to be traded.
            double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);
            if (exactVolume >= Symbol.VolumeInUnitsMin)
            {
                _volume = Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down);

                // Finally, check that the calculated volume is not greater than the MaxVolume parameter. If it is greater, reduce the volume to the MaxVolume value.
                if (_volume > MaxVolume)
                    _volume = MaxVolume;
                }
                else
                {
                _volume = -1;
                Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
            }
            return _volume;
        }


@Alwin123