Topics
Forum Topics not found
Replies
amusleh
24 May 2022, 12:06
( Updated at: 24 May 2022, 12:18 )
Hi,
Why is it not supported anymore, what's the reason behind it? It's more like a hidden feature that was removed if anything.
It shouldn't be supported on the first place at all, you were able to use non supported parameter type because there was a bug on validation of indicator parameters that were initialized by GetIndicator method, and now it's fixed.
There is another similar case, in version 4.2 you can't access or call any API member from another thread, you have to use BeginInvokeOnMainThread method, due to this changes lots of indicators/cBots stopped working, but it was not a compatibility issue, it was a bug on 4.1 and it was fixed, we have stated several times on Automate API documentation that it's not thread safe but users continued to access the API members from other threads and it was working just by luck, now we have a check and it doesn't allow access from other threads.
What are other ways of passing parameters to the indicator constructor if not by decorating it with ParameterAttribute and then passing it to the GetIndicator method?
Indicator instances are created by API itself, you don't create an instance by calling the indicator constructor, so there is no way to pass an object to an indicator or cBot constructor, there was never such a feature and if you tried to find some hacks and it was working on version 4.1 there is no guarantee that it will continue to work.
You can't pass anything to an indicator or cBot before it's OnStart/Initialize method is called, this is a limitation of API and you should not try to find a workaround to bypass it.
You have to develop your cBots/Indicators by considering the API limitations, not by bypassing them.
What's the proper way of initializing internal indicators if not by using the GetIndicator?
What's an internal indicator? there should be no internal indicator, this is my first time I'm seeing an indicator inside another indicator assembly, GetIndicator method is for initializing referenced indicators not for creating new indicator class inside another indicator.
Because there are relations between the objects, C# is an object-oriented programming language. Can you modify the sample code in the first post using the technique you are describing? I am failing to understand the solution you are proposing.
I will change your design completely if it was on me I would not designed that indicator like that on the first place, you have to ask what you want to solve? what's the problem? then implement your solution based on limitations of your environment, what you did was a temporary hack the bypasses the environment limitations not solving the issue.
Indeed C# is an OOP language, but you are using a service that is not developed by you and it has it's own limitations.
Here is how I developed your indicator:
using cAlgo.API;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None)]
public class UnsupportedParameterType : Indicator
{
[Output("Result")]
public IndicatorDataSeries Result { get; set; }
private Range _range;
protected override void Initialize()
{
_range = new Range(Bars);
}
public override void Calculate(int index)
{
Result[index] = _range.GetCalculationValue(index);
}
}
internal class Range
{
private readonly Bars _bars;
public Range(Bars bars)
{
_bars = bars;
}
public double GetCalculationValue(int index)
{
var bar = _bars[index];
return bar.High - bar.Low;
}
}
}
I need to pass an object to an indicator in the constructor, using static variables is not acceptable.
You can pass an object to another object via it's constructor if you are calling the constructor, you don't call the indicator/cBot constructor, then how you want to pass anything to it?
This is simple logic, I have developed a ton of cTrader indicators/cBots and I have never tried something that you did, it all depends on your software design and architecture skills.
The problem you are trying to solve is not passing objects to an indicator constructor, you want to send some data to another indicator instance, for that you have several options:
- Public properties
- Static data available on a separate class if you want to have access to the data during indicator initialization
Hopefully my words were useful for you.
@amusleh
amusleh
24 May 2022, 11:16
Hi,
Try this:
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;
using cAlgo.Indicators;
using System.Threading;
namespace cAlgo.Robots
{
[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SuperTrendReference_cBot : Robot
{
[Parameter(DefaultValue = "SuperTrendReference_cBot")]
public string cBotLabel { get; set; }
[Parameter("Serial Key", DefaultValue = "12")]
public string SerialKey { get; set; }
[Parameter("Trade Volume,in lots:", DefaultValue = 0.5, MinValue = 0.001)]
public double Lots { get; set; }
[Parameter("Martingale - Yes/No:", DefaultValue = true)]
public bool UseMartingale { get; set; }
[Parameter("Multiplication Factor:", DefaultValue = 1.5)]
public double MultiplicationFactor { get; set; }
[Parameter("Tolerance - Yes/No:", DefaultValue = true)]
public bool UseTolerance { get; set; }
[Parameter("Tolerance in pips:", DefaultValue = 10.0)]
public double TolerancePips { get; set; }
[Parameter("ATR Period", Group = ("Super Trend Indicator Inputs"), DefaultValue = 14)]
public int ST_Period { get; set; }
[Parameter("ATR Multiplier", Group = ("Super Trend Indicator Inputs"), DefaultValue = 2)]
public double ST_atrMulti { get; set; }
[Parameter("ATR Source", Group = ("Super Trend Indicator Inputs"), DefaultValue = MovingAverageType.Exponential)]
public MovingAverageType ST_AtrSource { get; set; }
[Parameter("Trading Start Hour:0-23", Group = ("Trading Hours"), DefaultValue = 11, MinValue = 0, MaxValue = 23, Step = 1)]
public int StartTimeHour { get; set; }
[Parameter("Trading Start Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int StartTimeMinute { get; set; }
[Parameter("Trading End Hour:0-23", Group = ("Trading Hours"), DefaultValue = 17, MinValue = 0, MaxValue = 23, Step = 1)]
public int EndTimeHour { get; set; }
[Parameter("Trading End Minute:0-59", Group = ("Trading Hours"), DefaultValue = 0, MinValue = 0, MaxValue = 59, Step = 1)]
public int EndTimeMinute { get; set; }
[Parameter("Max Drawdown,in %:", DefaultValue = 10.0)]
public double MaxDDPrct { get; set; }
[Parameter("Coffee Break - Yes/No:", DefaultValue = true)]
public bool UseCoffeeBreak { get; set; }
[Parameter("Profit:", DefaultValue = 500.0)]
public double CBProfit { get; set; }
[Parameter("RSI Signal bar", DefaultValue = 1, MinValue = 0)]
public int SignalBar { get; set; }
private SuperTrendExperto SuperTrend_;
private double currentTradeLots;
private DateTime StartTimeHour_;
private DateTime EndTimeHour_;
private DateTime StartTimeMinute_;
private DateTime EndTimeMinute_;
private double InitialDDAccountBalance;
private double CurrentClosedPosBal;
protected override void OnStart()
{
if (SerialKey != "0")
{
Print("Serial Key is NOT valid!");
Stop();
}
SuperTrend_ = Indicators.GetIndicator<SuperTrendExperto>(ST_Period, ST_atrMulti, ST_atrMulti);
if (UseMartingale == true)
{
currentTradeLots = Lots;
}
StartTimeHour_ = Server.Time.Date.AddHours(StartTimeHour);
EndTimeHour_ = Server.Time.Date.AddHours(EndTimeHour);
StartTimeMinute_ = Server.Time.Date.AddMinutes(StartTimeMinute);
EndTimeMinute_ = Server.Time.Date.AddMinutes(EndTimeMinute);
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
protected override void OnTick()
{
if (IsReach_DDPrct(MaxDDPrct) == true)
{
CloseAllPositions(TradeType.Buy);
CloseAllPositions(TradeType.Sell);
Print("DD is Hit!");
InitialDDAccountBalance = Account.Balance;
CurrentClosedPosBal = 0.0;
}
}
protected override void OnBar()
{
if (IsTradingHours() == true)
{
if (SuperTrend_.LowLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Buy) == 0)
{
CloseAllPositions(TradeType.Sell);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Sell);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Buy, currentTradeLots);
else
OpenMarketOrder(TradeType.Buy, Lots);
}
else if (SuperTrend_.HighLine.Last(SignalBar) > 0.0 && CalculatePositionsQnty(TradeType.Sell) == 0)
{
CloseAllPositions(TradeType.Buy);
if (UseMartingale == true)
UpdateTradeVolume(TradeType.Buy);
if (UseMartingale == true)
OpenMarketOrder(TradeType.Sell, currentTradeLots);
else
OpenMarketOrder(TradeType.Sell, Lots);
}
}
}
private void OpenMarketOrder(TradeType tradeType, double dLots)
{
var volumeInUnits = Symbol.QuantityToVolumeInUnits(dLots);
volumeInUnits = Symbol.NormalizeVolumeInUnits(volumeInUnits, RoundingMode.Down);
//in final version need add attempts counter
var result = ExecuteMarketOrder(tradeType, Symbol.Name, volumeInUnits, cBotLabel, null, null);
if (!result.IsSuccessful)
{
Print("Execute Market Order Error: {0}", result.Error.Value);
}
Stop();
}
private int CalculatePositionsQnty(TradeType tradeType)
{
return Positions.FindAll(cBotLabel, Symbol.Name, tradeType).Length;
}
private void CloseAllPositions(TradeType tradeType)
{
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name, tradeType))
{
var result = ClosePosition(position);
if (!result.IsSuccessful)
{
Print("Closing market order error: {0}", result.Error);
}
}
}
private bool IsReach_DDPrct(double DDPrctValue)
{
return ((CalculatePL() + CurrentClosedPosBal) <= (-1.0 * InitialDDAccountBalance * DDPrctValue / 100.0));
}
private double CalculatePL()
{
double CurrentPL = 0.0;
foreach (var position in Positions.FindAll(cBotLabel, Symbol.Name))
{
CurrentPL += position.NetProfit;
}
return CurrentPL;
}
private bool IsTradingHours()
{
var currentTimeHour = Server.Time.TimeOfDay.Hours;
var currentTimeMinute = Server.Time.TimeOfDay.Minutes;
if ((StartTimeHour_.Hour < currentTimeHour && EndTimeHour_.Hour > currentTimeHour) || (StartTimeHour_.Hour == currentTimeHour && StartTimeMinute_.Minute <= currentTimeMinute) || (EndTimeHour_.Hour == currentTimeHour && EndTimeMinute_.Minute >= currentTimeMinute))
return true;
return false;
}
private void UpdateTradeVolume(TradeType tradeType)
{
RefreshData();
HistoricalTrade lastClosedPosition = History.FindLast(cBotLabel, Symbol.Name, tradeType);
if (lastClosedPosition == null)
return;
CurrentClosedPosBal += lastClosedPosition.NetProfit;
if ((UseTolerance == false && lastClosedPosition.NetProfit > 0.0) || (UseTolerance == true && lastClosedPosition.Pips > TolerancePips))
{
currentTradeLots = Lots;
}
else
{
if (UseTolerance == false || (UseTolerance == true && lastClosedPosition.Pips < (-1.0 * TolerancePips)))
{
currentTradeLots *= MultiplicationFactor;
}
else
{
//same lot size
}
}
if (UseCoffeeBreak == true && lastClosedPosition.NetProfit > CBProfit)
{
Print("Coffee Break is Hit!");
Stop();
}
}
protected override void OnStop()
{
Stop();
}
}
}
@amusleh
amusleh
24 May 2022, 10:41
RE: RE:
123123 said:
amusleh said:
Hi,
When you scroll to the left cTrader automatically loads more data, there is no need for coding anything.
If it's not behaving like that then something is wrong, can you tell me which broker you are using?
Hi,
Something definitely wrong because I have never experienced this on cTrader, the broker is FTMO.
Hi,
Can you reproduce this same issue on other brokers cTrader desktops?
Maybe your broker has that much data for that symbol, and there is no more historical data.
@amusleh
amusleh
24 May 2022, 10:40
RE:
Jiri said:
Hi @amusleh,
Thanks for the response. It appears to me that the prior version of cTrader was checking the parameter type only if the class was decorated with the IndicatorAttribute. This makes sense because of the rendering UI components. But if there is a non-public indicator used internally only, without the UI, why would it require the limited parameter type? It does not feel like this was a bug, everything was working as expected. Can you suggest a workaround to pass custom parameter types that would be assigned prior to the Initialize state?
Hi,
It's definitely a bug on cTrader 4.2 that allows you to use not support parameter type.
You are using Parameter attribute in a way that is not meant to be used nor documented.
And you are also using GetIndicator incorrectly, it should only be used when you are using a referenced external indicator, not an indicator that resides on your current indicator assembly.
Regarding a solution, it's very simple, change your indicator design, use API members properly, why you need another indicator inside your current indicator assembly?
The problem you are trying to solve is you want to exchange data between two indicators, you can use static properties for it which is the simplest option.
If you need a sample check our Synchronized Indicators:
@amusleh
amusleh
24 May 2022, 10:28
Hi,
This works fine on both cTrader 4.1 and 4.2:
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using System.Linq;
namespace cAlgo
{
[Indicator("Support and Resistance At Price", IsOverlay = true, AccessRights = AccessRights.None)]
public class SRAtPrice : Indicator
{
private double extremeHigh = 0;
private double extremeLow = 0;
private double dayHi = 0;
private double dayLo = 0;
private SortedList<double, int> prices = new SortedList<double, int>();
private IList<Zone> zones = new List<Zone>();
private const string ExtremeHighName = "ExtremeHigh";
private const string ExtremeLowName = "ExtremeLow";
private const string DayHighName = "DayHigh";
private const string DayLowName = "DayLow";
[Parameter("Periods", DefaultValue = 100)]
public int Periods { get; set; }
[Parameter("Show Extreme H/L", DefaultValue = true)]
public bool ShowExtremeHL { get; set; }
[Parameter("Show Day H/L", DefaultValue = true)]
public bool ShowDayHL { get; set; }
[Parameter("Required Hits", DefaultValue = 0)]
public int RequiredHits { get; set; }
[Parameter("Zone Size", DefaultValue = 2)]
public int ZoneSize { get; set; }
[Parameter("Max Lines In Zone", DefaultValue = 1)]
public int MaxLinesInZone { get; set; }
[Output("Extreme H/L Style", Color = Colors.Red, LineStyle = LineStyle.DotsVeryRare)]
public IndicatorDataSeries ExtremeHLStyle { get; set; }
[Output("Day H/L Style", Color = Colors.Blue, LineStyle = LineStyle.DotsVeryRare)]
public IndicatorDataSeries DayHLStyle { get; set; }
[Output("S/R Style", Color = Colors.Orange, LineStyle = LineStyle.DotsVeryRare)]
public IndicatorDataSeries SRStyle { get; set; }
public override void Calculate(int index)
{
if (this.IsLastBar)
{
var currentOpenDate = this.MarketSeries.OpenTime[index].Date;
var earliest = index - this.Periods;
for (var i = index; i >= earliest; i--)
{
if (i >= 0)
{
var high = this.MarketSeries.High[i];
var nextHigh = this.MarketSeries.High[i + 1];
var low = this.MarketSeries.Low[i];
var nextLow = this.MarketSeries.Low[i + 1];
this.extremeHigh = Math.Max(high, this.extremeHigh);
this.extremeLow = this.extremeLow == 0 ? low : Math.Min(low, this.extremeLow);
if (this.TimeFrame < TimeFrame.Minute)
{
if (this.MarketSeries.OpenTime[i].Date == currentOpenDate)
{
this.dayHi = Math.Max(high, this.dayHi);
this.dayLo = this.dayLo == 0 ? low : Math.Min(low, this.dayLo);
}
}
if (nextHigh <= high)
{
this.AddOrUpdatePrice(high);
}
if (nextLow >= low)
{
this.AddOrUpdatePrice(low);
}
}
else
{
break;
}
}
this.zones.Clear();
var rangePipSize = (this.Symbol.PipSize * (double)this.ZoneSize);
for (var i = this.extremeLow + rangePipSize; i < this.extremeHigh - rangePipSize; i += rangePipSize + this.Symbol.PipSize)
{
this.zones.Add(new Zone
{
Start = i,
End = i + rangePipSize,
LinesRendered = 0
});
}
var chartObjectCopy = Chart.Objects.ToArray();
foreach (var chartObject in chartObjectCopy)
{
Chart.RemoveObject(chartObject.Name);
}
foreach (var price in this.prices.Keys)
{
this.RenderSRIfRequred(price, this.prices[price]);
}
if (this.ShowExtremeHL)
{
this.DrawExtremeHigh();
this.DrawExtremeLow();
}
if (this.TimeFrame < TimeFrame.Minute && this.ShowDayHL)
{
this.DrawDayHigh();
this.DrawDayLow();
}
}
}
private void RenderSRIfRequred(double price, int count)
{
if (count < this.RequiredHits)
{
return;
}
foreach (var range in this.zones)
{
if (price >= range.Start && price <= range.End)
{
if (range.LinesRendered != this.MaxLinesInZone)
{
range.LinesRendered++;
this.DrawSR(price);
}
return;
}
}
}
private void AddOrUpdatePrice(double priceValue)
{
if (this.prices.ContainsKey(priceValue))
{
this.prices[priceValue]++;
}
else
{
this.prices.Add(priceValue, 1);
}
}
private void DrawExtremeHigh()
{
this.DrawExtreme(ExtremeHighName, this.extremeHigh);
}
private void DrawExtremeLow()
{
this.DrawExtreme(ExtremeLowName, this.extremeLow);
}
private void DrawDayHigh()
{
this.DrawDay(DayHighName, this.dayHi);
}
private void DrawDayLow()
{
this.DrawDay(DayLowName, this.dayLo);
}
private void DrawExtreme(string name, double level)
{
var attribute = this.GetAttributeFrom<OutputAttribute>("ExtremeHLStyle");
this.ChartObjects.DrawHorizontalLine(name, level, attribute.Color, attribute.Thickness, attribute.LineStyle);
}
private void DrawDay(string name, double level)
{
var attribute = this.GetAttributeFrom<OutputAttribute>("DayHLStyle");
this.ChartObjects.DrawHorizontalLine(name, level, attribute.Color, attribute.Thickness, attribute.LineStyle);
}
private void DrawSR(double level)
{
var attribute = this.GetAttributeFrom<OutputAttribute>("SRStyle");
this.ChartObjects.DrawHorizontalLine(string.Format("SR {0}", level), level, attribute.Color, attribute.Thickness, attribute.LineStyle);
}
private T GetAttributeFrom<T>(string propertyName)
{
var attrType = typeof(T);
var property = this.GetType().GetProperty(propertyName);
return (T)property.GetCustomAttributes(attrType, false).GetValue(0);
}
private class Price
{
internal double Value { get; set; }
internal int Count { get; set; }
}
private class Zone
{
internal double Start { get; set; }
internal double End { get; set; }
internal int LinesRendered { get; set; }
}
}
}
@amusleh
amusleh
24 May 2022, 10:21
Hi,
Your code is not correct, your indicator should not work at all, not sure how it was working previously.
You are passing index + x to Bars Last method, the last method starts from 1 and it allows you to access bars in reverse order from most recent bars.
If you want to access three last bars you have to change it to:
using cAlgo.API;
using System.Linq;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ThreeStrike : Indicator
{
[Parameter("Vertical Alignment", Group = "Position", DefaultValue = VerticalAlignment.Top)]
public VerticalAlignment vAlignment { get; set; }
[Parameter("Horizontal Alignment", Group = "Position", DefaultValue = HorizontalAlignment.Right)]
public HorizontalAlignment hAlignment { get; set; }
private ChartStaticText _text;
protected override void Initialize()
{
_text = Chart.DrawStaticText("idtext_red", string.Empty, this.vAlignment, this.hAlignment, Color.Chocolate);
}
public override void Calculate(int index)
{
if (index < 3)
return;
var lastThreeBars = new Bar[]
{
Bars.Last(1),
Bars.Last(2),
Bars.Last(3)
};
if (lastThreeBars.All(bar => bar.Close > bar.Open))
{
_text.Text = "Wait For Red Engulfing";
_text.Color = Color.Red;
if (Bars.ClosePrices.Last(index) < Bars.OpenPrices.Last(index++))
{
_text.Text = "Sell";
_text.Color = Color.Red;
Chart.DrawVerticalLine("Sell", Bars.OpenTimes.LastValue, Color.OrangeRed);
}
}
else if (lastThreeBars.All(bar => bar.Close < bar.Open))
{
_text.Text = "Wait For Green Engulfing";
_text.Color = Color.Green;
if (Bars.ClosePrices.Last(index) > Bars.OpenPrices.Last(index++))
{
_text.Text = "Buy";
_text.Color = Color.Green;
Chart.DrawVerticalLine("Buy", Bars.OpenTimes.LastValue, Color.LimeGreen);
}
}
else
{
_text.Text = "Do Not Trade";
_text.Color = Color.Gray;
}
}
}
}
@amusleh
amusleh
24 May 2022, 10:14
RE: problem solved bij reinstalling cTrader
genappsforex said:
amusleh said:
Hi,
The lines are discontinuous:
After closing all copies of cTrader and reinstalling cTrader it It now gives the discontinuous lines as it should.
Hi,
The image I posted is from your own indicator and as you can see it was working fine on my system.
@amusleh
amusleh
24 May 2022, 10:13
Hi,
Then decrease the index by 1:
using cAlgo.API;
namespace cAlgo
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None, TimeZone = TimeZones.EAfricaStandardTime)]
public class Spring : Indicator
{
[Output("Up Fractal", Color = Colors.Red, PlotType = PlotType.Points, Thickness = 5)]
public IndicatorDataSeries UpFractal { get; set; }
[Output("Down Fractal", Color = Colors.Blue, PlotType = PlotType.Points, Thickness = 5)]
public IndicatorDataSeries DownFractal { get; set; }
private Bars HSeries;
protected override void Initialize()
{
HSeries = MarketData.GetBars(TimeFrame.Hour4);
}
public override void Calculate(int index)
{
if (index == 1)
return;
DrawUpFractal(index);
DrawDownFractal(index);
}
private void DrawUpFractal(int index)
{
var hSeriesIndex = HSeries.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - 1;
int middleIndex = hSeriesIndex - 2;
double middleValue = HSeries.ClosePrices[middleIndex];
bool up = false;
for (int i = 1; i < HSeries.ClosePrices.Count - 1; i++)
{
if (HSeries.ClosePrices[middleIndex] > HSeries.ClosePrices[middleIndex - 1] && HSeries.ClosePrices[middleIndex] > HSeries.ClosePrices[middleIndex + 1])
{
up = true;
break;
}
}
if (up)
UpFractal[index] = middleValue;
}
private void DrawDownFractal(int index)
{
var hSeriesIndex = HSeries.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]) - 1;
int middleIndex = hSeriesIndex - 2;
double middleValue = HSeries.ClosePrices[middleIndex];
bool down = false;
for (int i = 1; i < HSeries.ClosePrices.Count - 1; i++)
{
if (HSeries.ClosePrices[middleIndex] < HSeries.ClosePrices[middleIndex - 1] && HSeries.ClosePrices[middleIndex] < HSeries.ClosePrices[middleIndex + 1])
{
down = true;
break;
}
}
if (down)
DownFractal[index] = middleValue;
}
}
}
@amusleh
amusleh
24 May 2022, 10:12
Hi,
I just tested this on M1 chart:
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(AccessRights = AccessRights.FullAccess)]
public class NewcBot3 : Robot
{
protected override void OnStart()
{
Print("Started Bot...");
var firstResult = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
if (!firstResult.IsSuccessful)
{
Print("First Order not placed successfully");
}
var secondResult = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin);
if (!secondResult.IsSuccessful)
{
Print("Second Order not placed successfully");
}
}
protected override void OnBar()
{
Print("OnBar Executed on.. " + Chart.TimeFrame);
Print("Positions Length=" + Positions.Count);
foreach (var position in Positions)
{
if (position.SymbolName != SymbolName) continue;
Print("Position Entry Time=" + position.EntryTime);
ClosePosition(position);
}
}
}
}
All positions were closed without any issue.
@amusleh
amusleh
24 May 2022, 10:06
Hi,
The way you are using indicator parameters is not correct, it looks like it was working by luck and most probably it was a bug on version 4.1.
You can find the list of supported parameter types at: Indicator Code Samples - cTrader Automate API Documentation (spotware.github.io)
You can only use one of those types as a parameter.
@amusleh
amusleh
24 May 2022, 08:44
RE: RE:
genappsforex said:
ctid2032775 said:
A little bit strange is that as soon as I switch to .NET 6, run any bot and close the cTrader application the cTrader process is not terminated, as well.
I noticed that too, This behaviour eats Memory and CPU . Think they're forgetting to clean up/Close old threads.
Hi,
We can only help you if we were able to reproduce the issues you are facing, if we can't then there is no way for us to know what's going wrong.
@amusleh
amusleh
24 May 2022, 12:23
RE: RE:
m4trader4 said:
Hi,
Try this:
@amusleh