Topics
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
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
oliver.r.m.92
20 Feb 2024, 19:19
RE: Amount to trade depending on stop loss
PanagiotisCharalampous 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;
}
}
}
@oliver.r.m.92