Amount to trade depending on stop loss
Amount to trade depending on stop loss
19 Feb 2024, 19:13
I am trying to configure a cBot so that regardless of the stop loss pips, it represents a loss of 1% of the account balance, I need it to make this calculation and operate with the appropriate amount in each case adapting to the stop loss (Something like the position tool in tradingview that calculates the amount to operate depending on your stop loss). When configuring it the way it appears in the code, the cBot does not execute any order and I do not know where the error is, I would appreciate your help. Thank you!
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; } }}
Replies
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
PanagiotisCharalampous
20 Feb 2024, 10:23
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);
@PanagiotisCharalampous
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
firemyst
21 Feb 2024, 01:38
RE: RE: Amount to trade depending on stop loss
oliver.r.m.92 said:
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;
}
}
}
Of course it throws an error. Look at your code in OnBar.
Look at the code you ALWAYS execute regardless if you're in a position or not.
Where do you set stopLossPrice (I bolded it in the code above) if you don't have any positions? You're trying to do a calculation using it when you're not setting it.
I also suggest you starting learning how to use Print statements in your code to print values to the log. THen if you put print statements everywhere, you also know where your code is crashing.
@firemyst
PanagiotisCharalampous
20 Feb 2024, 06:57
Hi there,
Please provide the code in proper format so that we can easily copy, paste and build it.
Best regards,
Panagiotis
@PanagiotisCharalampous