How to calculate trading volume, based on stop loss.
How to calculate trading volume, based on stop loss.
23 Apr 2021, 17:09
What is the correct and/or an elegant way, to compute trading volume based on stop loss, such that when the symbol, lot size or account leverage is changed, the math always computes the correct trading volume to populate the volume parameter of the Robot.PlaceLimitOrder method.
Question 1:
- How to compute trading volume based on stop loss, such that the correct value is returned regardless of symbol, lot size and leverage?
- One issue I am experiencing, is that during truncation of the computed trading volume, I find my self having to multiply the truncation factor by a constant value of 100 for some reason.
- No matter how I compute the trading volume, when I truncate to get a multiple of the lot size, 100,000 in the case of the example below, I keep having to introduce this constant factor of 100.
- Ideally the relationships between the relevant variables should be enough to compute the result with out having to introduce any constants. Unless the value of 100 has some significance, which up until now I have been unable to determine.
Question 2:
- How does account leverage affect trading volume?
- So far I am unable to find a relationship between account leverage and trading volume, although my intuition suggests there should be a relationship between the two.
Question 3:
- Why does Symbol.PipValue not change to 0.01, when the symbol is changed to a JPY pair?
- When I change from EUR-USD to USD-JPY, Symbol.PipValue still returns a value of 0.0001.
- Shouldn't Symbol.PipValue return a value of 0.01 for USD-JPY?
Question 4:
- Where is lot size set?
- The lot size seems to always be set to the standard lot size of 100,000. How does one set lot size to mini, micro or nano lot sizes?
Calculations:
- For reference, here is how I am currently computing trading volume now.
- For the sake of this example, I am operating on EUR-USD, with 1:100 leverage. Although I do not yet know how to incorporate leverage into the calculations below.
[1] Compute amount of trading account to risk per trade:
- risk_percentage = 1 %
- account_ballance = $ 10,183.89
[2] Compute real value of trade volume:
- pip_scale = 0.0001 ...For EUR-USD. Retrieved in code with, Symbol.PipValue.
- stop_loss = 20 pips ...Computed in code, but we'll just use 20 for the sake of this example.
[3] Compute trade volume truncation factor:
- lot_size = 100,000 ...Standard lot size. Retrieved in code with, Symbol.LotSize.
- pip_scale = 0.0001 ...For EUR-USD. Retrieved in code with, Symbol.PipValue.
- Constant factor = 100 ...Unidentified constant. Why do we need to multiply the truncation factor by 100?
[4] Compute truncated trade volume, that can be used to populate the "volume" parameter of the Robot.PlaceLimitOrder method:
We can now use a value of 50,000 as the argument, for the volume parameter ofthe Robot.PlaceLimitOrder method.
Code:
- For reference, here is the code that I have implemented so far.
//------------------------------------------------------------------------------------------------------------------------------------------------------
// Method:
// - ComputeTradeVolume
//
// Description:
//
// - Compute trade volume, in units that can be used to pupulate the "volume" parameter of the "Robot.PlaceLimitOrder" cBot API method.
//
// - Calculations:
//
// [1] Compute the portion of the trading account to risk.
// ▪ This will be used as the basis for the stop loss we select.
// ▪ The final stop loss will be increased to acomodate spread and commissions.
//
// ╭ ╮
// │ risk_percentage │
// amount_to_risk_per_trade = account_ballance x │ ─────────────── │
// │ 100 │
// ╰ ╯
//
//
// [2] Compute the real number value of the trade volume for this trade.
// ▪ We won't be able to use this value directly to populate the "volume" parameter of
// the "Robot.PlaceLimitOrder" method, as the value we use to populate
// Robot.PlaceLimitOrder's "volume" parameter, will need to be a multiple of the lot
// size, for example, a standard lot size of 100,000.
// ▪ To prepare the trade volume for use in the "Robot.PlaceLimitOrder" method, we will
// truncate the value to the nearest lot size in the next step.
// ▪ pip_scale is 0.0001 for EUR-USD, and 0.01 for USD-JPY, XAU-USD, etc.
//
// amount_to_risk_per_trade
// trade_volume = ────────────────────────────
// stop_loss_pips x pip_scale
//
//
// [3] Compute the trading volume truncation factor.
// ▪ To truncate the trade volume so that it is compatible with the "volume" parameter
// of the "Robot.PlaceLimitOrder" method, we will need to compute a truncation
// factor.
// ▪ Note:
// - At present, we have to multiply the truncation factor by 100 to get the equation
// to work.
// - It is currently not known, why a value of 100 needs to be multiplied to the
// truncation factor to get the equations to work.
// ▪ lot_size = 100,000, and 100 is a 'currently unidentified' constant.
//
// truncation_factor = lot_size x pip_scale x 100
//
//
// [4] Teuncate the trading volume computed in step [2].
// ▪ We use the truncation factor computed in step [3], to truncate the trading volume,
// so that the we can use it to populate the "volume" parameter of the
// "Robot.PlaceLimitOrder" cBot API method
// ▪ We employ standard truncation, by multiplying the truncation factor by the floor
// of the trading volume divided by the truncation factor.
//
// │ trade_volume │
// trade_volume_truncated = │ ───────────────── │ x truncation_factor
// │ truncation_factor │
// └── ──┘
//
// Parameters:
//
// - stop_loss_pips
// Stop loss expressed as an integer representation of the stop loss in pips.
// Example:
// - If the real value os the stop loss is 0.0025, then the parameter stop_loss will be
// populated with the integer 25, to denote 25 pips.
//
// Return Value:
// - Trade volume expressed as an integer, to represent the trade volume in units of the quote
// currency.
//
//------------------------------------------------------------------------------------------------------------------------------------------------------
protected int ComputeTradeVolume ( int stop_loss_pips )
{
// Compute trade amount to risk.
double account_ballance = Account.Balance;
double risk_percentage = this.RiskPercentage;
double amount_to_risk_per_trade = account_ballance * ( risk_percentage / 100.0 );
// Calculate trade volume.
double pip_scale = Symbol.PipValue;
double trade_volume = amount_to_risk_per_trade / ( stop_loss_pips * pip_scale );
// Truncating trade volume to the nearest lot size.
// - We need to truncate the computed trading volume, so that we can express the trading volume as a multiple of lot size.
// - Issue:
// - When computing the truncation factor, we have to multiple the truncation factor by 100 to get it to work.
// - Why do we have to multiply by 100?
double lot_size = Symbol.LotSize;
double truncation_factor = lot_size * pip_scale * 100;
double trade_volume_truncated = ( (int) ( trade_volume / truncation_factor ) ) * truncation_factor;
// Print variables to cTrader automate Log.
if ( this.DEBUG_ENABLED )
{
LogComputeTradeVolume
(
account_ballance,
risk_percentage,
amount_to_risk_per_trade,
pip_scale,
lot_size,
stop_loss_pips,
trade_volume,
truncation_factor,
(int) trade_volume_truncated
);
}
// Return truncated trade volume to caller.
return ( (int) trade_volume_truncated );
}
//--------------------------------------------------------------------------------------------------------------------------------------------
// Method: OnStart
//
// Descripion:
// - cBot "on start" event.
// - The code below is to test the "ComputeTradeVolume" method.
//
//--------------------------------------------------------------------------------------------------------------------------------------------
protected override void OnStart()
{
// Compute trade volume.
// - We sill just use a stop loss of 20 pips for this example.
int stop_loss_pips = 20;
int trade_volume_truncated = ComputeTradeVolume ( stop_loss_pips );
// Place test limit order, to check computation results.
TradeType trade_direction = TradeType.Buy;
string trading_pair = Symbol.Name;
string position_lable = "TEST_POSITION";
double price = Bars.ClosePrices.Last ();
double pip_scale = Symbol.PipValue;
double target_price_delta = stop_loss_pips * pip_scale * 0.25; // Set the target price to 1/4 of the stop loss.
double target_price = price - target_price_delta;
double take_profit_pips = stop_loss_pips * 3.0; // We will use a risk reward ratio of 1:3 for this test trade.
PlaceLimitOrder
(
trade_direction, // Buy
trading_pair, // EUR-USD
trade_volume_truncated, // Truncated trade volume, expressed as a multiple of lot size.
target_price, // Target price is 1/4 the stop loss value, as computed above.
position_lable, // Order lable.
stop_loss_pips, // SL, at 1:3 risk reward ratio, as computed above.
take_profit_pips // TP, at 1:3 risk reward ratio, as computed above.
);
// Stop the robot.
Stop ();
}
Robot Output:
- When the test robot (code above) is run, we get the following output printed to the cTrader automation log.
Example Limit Order:
- The following example limit order was created using trading volume computed by the ComputeTradingVolume method in the code above.
Replies
rohingosling
24 Apr 2021, 22:12
RE: Multiplying account balance by 100
Hi Amusleh,
Thank you, this helps enormously.
One question regarding the code example you shared. The account balance is always multiplied by 100. Why is that? Is it to convert it to cents?
Regards,
Rohin
@rohingosling
amusleh
25 Apr 2021, 11:20
( Updated at: 21 Dec 2023, 09:22 )
RE: RE: Multiplying account balance by 100
rohingosling said:
Hi Amusleh,
Thank you, this helps enormously.
One question regarding the code example you shared. The account balance is always multiplied by 100. Why is that? Is it to convert it to cents?
Regards,
Rohin
For converting the Percent from decimal form to 0-100 form or vice versa.
@amusleh
... Deleted by UFO ...
amusleh
24 Apr 2021, 12:02
Hi,
Question 1:
Please check this file code:
Question 2: Leverage decreases the cost of buying something for you and allows you to have more free equity, so you will be able to buy something with much lower equity of your account total available equity if you have higher leverage.
Question 3. PipValue is the amount of monetary value for one single Pip of a symbol in your account currency, you should use PipSize if you want to get the symbol Pip, in your case one Pip of USDJPY will cost you 0.0001 of your account currency for one single unit of volume, so it means if you buy 1 unit of volume of USDJPY one pip will cost you 0.0001 of your account currency.
Question 4. cTrader uses standard lot size and volume units, there is no micro, nano or other non-standard lot sizes, the minimum/maximum trading volume for symbols and all other symbols data are set by your broker.
@amusleh