Topics
Replies
firemyst
22 Feb 2022, 12:17
protected override void OnTick()
{
//This is all you would have had to do:
double a = S2.sell_ONE.Last(0);
a = S2.liq_ONE.Last(0);
//That's it! Now the Calculate method has been
//forced to calculate for each sell_One and liq_one.
//You can now get any values from your indicator
//and they will be readily available.
var index = Bars.Count - 1;
var indicatorIndex = index - 2;
Chart.RemoveObject(indicatorIndex.ToString());
if (double.IsNaN(S2.sell_ONE[indicatorIndex]) == false)
{
Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#B511F7"));
}
else if (double.IsNaN(S2.liq_ONE[indicatorIndex]) == false)
{
Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#FF7CFC00"));
}
}
See code example above. It's not really necessary with amusleh's rewrite, but it illustrates the point. It's literally that simple. You'd have to do that for any other custom indicator you need values for.
Advice is to put all those calls into one method, and then just call the method at OnTick, OnBar, or whenever you'll need values from your indicators.
@firemyst
firemyst
22 Feb 2022, 10:00
RE: RE:
BJORNBERNAU said:
Again, thank you.
I've just posted a broader inquiry on this issue.
https://ctrader.com/forum/indicator-support/37673
A new problem arises when I define a VAR as you suggest. How then is it converted into a IndicatorDataSeries which is defined as a parameter in the program? In doing so the Indicator doesn't work anymore.
And do we really have to go that far as to define the LAZY class to use this system?
Thank you!
You're doing it wrong, and I see you don't appear to understand some basic concepts.
I have no idea why you changed liq_one and sell_one to get a double value? Those are indicator data series, so leave them be!
You just have to FORCE the indicator to return a value. The value returned will be a double. So just create a new double variable and assign it an indicator value _before_ you actually need to compare values in your indicator data series.
As per the second article link I provided:
var a = S2.sell_ONE.Last(0);
or you could do:
double a = S2.sell_ONE.Last(0);
Do the same for liq_one right after the sell_one:
a = S2.liq_ONE.Last(0); //who cares if you overwrite the value in "a" because it's just a dummy to force the indicator to run the calculate method.
Now that you've forced the indicator to run the calculate method, just leave the rest of the code as you had it and all the indicator's values will be "full loaded". So you DO NOT have to do:
.a = S2.liq_ONE.Last(1);
.a = S2.liq_ONE.Last(2)
etc etc;
@firemyst
firemyst
22 Feb 2022, 02:38
HI @BJORNBERNAU
Running through Visual studio on a chart:
most of the data series in the indicator itself is NaN as you can see above.
In your bot you never get the latest indicator values before checking the latest indicator values.
It could the "lazy loading" of indicators from cbots as @Panagiotis mentioned in your thread here from Aug 3, 2020:
Also see the last post in this thread:
So you need to force the indicator to call the calculate method before you access any of the indicator's data series.
@firemyst
firemyst
21 Feb 2022, 15:16
( Updated at: 21 Feb 2022, 15:26 )
Glancing at your code, a possible problem is you never actually set the last value of either data series.
You only ever populate [index - 2] of either sell_One or liq_one, never [index].
Therefore:
s2.liq_one.last(0) is NAN
s2.sell_one.last(0) is NAN
s2.liq_one.last(1) is NAN
s2.sell_one.last(1) is NAN
so the .Last(0) values are both the same, hence the reason they both print out and don't alternate.
Similarly, the .Last(1) values are both the same too.
@firemyst
firemyst
18 Feb 2022, 07:08
There's at least two easy options:
1) save the values to a data file, and then read the values back in when you restart your bot. You'll probably want to save to an XML or Json file so you have easy parsers available.
2) not the best practice, but you can create static variable collections and reference those. As long as you don't close cTrader, they should be around. However, if you close down cTrader, you'll lose the values in those variables.
@firemyst
firemyst
14 Feb 2022, 14:41
RE: RE: RE: RE: RE: RE:
m4trader4 said:
cBot crashed: Error #90580554
cBot crashed: Error #65147970
If you check this thread:
according to @amusleh, this happens with high volatility. So again this probably comes back to your code trying to move/check a stop loss when the position could have been closed elsewhere.
This could happen either with ".HasValue" or ".Stoploss.GetValueOrDefault()".
It also says you need a flag in your code to see if the closing event has been fired. If it has, you can't go through, check positions, and modify stop losses because one of the positions in your foreach loop could have been closed between the time you check the length of the positions and go through the foreach loop.
@firemyst
firemyst
14 Feb 2022, 12:35
RE: RE: RE: RE: RE:
m4trader4 said:
@Firemyst
if (psnCBS.StopLoss.GetValueOrDefault() != 0) doesnt work, CBot crashes
@ cAlgoBuddy
psnCBS.StopLoss.HasValue is working CBot is not crashing.
Have to check when there is high volatility/Event
Define "doesn't work".
The only way it won't work is if psnCBS is null.
What's the error message thrown when the bot crashes?
@firemyst
firemyst
14 Feb 2022, 04:47
RE: RE:
m4trader4 said:
This is the second time i am writing as the first one after posting dint appear
Hi Firemyst
Thanks for pointers, will amend the code.
The issue i think is when there is high volatility CheckSLPositions() is unable to lock the postions list. The CBot running on other symbols is doing the same opening new trades/moving stoploss/checking Stoploss.
Its about the thread safe
Regards
Ahmed
Why would you need to lock the Positions object? All you're doing is reading it; you can't set any values in it. So it's not your problem. :-)
I don't understand why you would want, or have, a cbot running under multiple symbols that would adjust the stoploss for _ALL_ open positions and not just the one the bot is running under?
To resolve the "thread safety", just have this cbot running once under 1 symbol and that's it since it updates every position that's open.
So change this statement to only find the symbol's the bot is running under:
Positions.FindAll("") //change this
change the above to something like:
Positions.Find("", Symbol.Name); //return only the positions under the current symbol the bot instance is running under
If you insist or really need multiple instances of this bot to be running and updating all positions across all symbols, then one approach is to create a global lock object and lock that bit of code. KEep in mind the performance implications - like it'll slow down your other bots as they wait to obtain a lock. This isn't the most elegant or possibly best way, but here goes:
public static object myGlobalLockObject = new object();
:
:
lock (myGlobalLockObject)
{
if (positionsCBS != null and positionsCBS.Length > 0)
{
foreach ( ... )
{
}
}
}
@firemyst
firemyst
13 Feb 2022, 05:48
positionsCBS can be null, which is one reason you might be getting the null reference exception.
After all, when you start the bot, there might not be any positions open.
So you need to check if you have any positions:
if (positionsCBS != null && positionsCBS.Length != 0)
And if you want to check if a position has a stoploss or not, you need to use p.GetValueOrDefault()
That will return zero if there's no stop loss associated with the position.
So don't do this:
if (psnCBS.StopLoss.ToString() != "")
Do this instead:
if (psnCBS.StopLoss.GetValueOrDefault() != 0)
@firemyst
firemyst
08 Feb 2022, 15:31
RE:
nowewo5508 said:
PS : Is it possible to have the SL and TP choice buttons increase/decrease them by 1/10 of a pip rather than a full pip ? Haven't found how to configure that.
Yes.
Use the "step" attribute in the parameter as long as the parameter is declared as a "double" and not an "int".
Example:
[Parameter("Take Profit", DefaultValue = 15, MinValue = 1, Step = 0.1)]
public double TP { get; set; }
@firemyst
firemyst
08 Feb 2022, 15:22
You're trying to store the value from this:
Indicators.GetIndicator<FDGGCSMA>
which is an "FDGGCSMA" type into the variable "stochFast1", which is defined as an SMA:
private SimpleMovingAverage stochFast1;
We have no idea what you want to do, so the easiest thing to do is change the stochFast1 variable type:
private FDGGCSMA stochFast1;
@firemyst
firemyst
31 Jan 2022, 08:54
RE:
amusleh said:
Hi,
No, you can't, there is no way to re-initialize an indicator programmatically.
Please create a thread under suggestions section for this feature if you want to.
THanks amusleh ,
Just to confirm because maybe we're using different terms, I don't want to reinitialize the indicator per-se -- I just want to be able to display the indicator settings window programmatically. The user could close it without changing anything.
I don't think re-initializing occurs unless a user actually changes a parameter or setting in the pop-up config window before closing it or clicking "okay"?
@firemyst
firemyst
30 Jan 2022, 14:38
( Updated at: 21 Dec 2023, 09:22 )
RE:
PanagiotisCharalampous said:
Hi firemyst,
1) Yes
2) Yes
Best Regards,
Panagiotis
Is there a way, using the built in Dotfuscator tools that come with Visual Studio, to have the files obfuscated before they are compiled into the encrypted calgo files?
I haven't been successful in finding a way to compile a calgo project to a dll, run through the Dotfuscator, and then have it picked up and encrypted into a calgo file.
I know earlier in this thread you said it's pointless to obfuscate encrypted code, but I do have at least 2 clients who would like the code obfuscated regardless of how much cTrader encrypts.
Thank you.
@firemyst
firemyst
30 Jan 2022, 13:27
RE:
PanagiotisCharalampous said:
Hi firemyst,
Happy holidays! From the next update, there won't be any dependencies to the cTrader platform, therefore you will be able to use any IDE for .Net projects you wish.
Best Regards,
Panagiotis
To confirm (or not), will it support indicatror/cbot compilations in 64-bits? Or do we need to keep "any cpu / 32-bit" compilation options?
@firemyst
firemyst
28 Jan 2022, 17:23
RE: RE: RE:
amusleh said:
firemyst said:
Thanks amusleh ,
1) but that means we have what -- a total of 9 locations we can put controls on using the Horizontal/Vertical align parameters? Eg, Halign left valign top; halign right valign middle; etc etc.
2) Otherwise, when you say, "allow user change the location of controls by using indicator/cBot parameters", how do you mean? What parameters would you suggest? The Horizonal/Vertical align as in #1 above? Or something else?
3) And I noticed there appears to be no way to query the chart to see what controls are on the chart like we can query to find what "chart objects" are on the chart?
Hi,
1. No, you can use grids or any other panels, like canvas.
2. Yes, I mean the alignment properties.
3. For now there is no way to query chart controls, you can only add or remove them.
You can open a thread under suggestions section for your point #3 if you want to.
Thank you amusleh ,
That helps immensely.
@firemyst
firemyst
28 Jan 2022, 08:53
RE:
amusleh said:
Hi,
Your cBot/indicator doesn't know about other indicator/cBots controls, so you can't align your controls based on other indicators/cBots controls that are present on the chart.
The only option is to allow user change the location of controls by using indicator/cBot parameters, so he will be able to set the location somewhere that is free from other controls.
Thanks amusleh ,
1) but that means we have what -- a total of 9 locations we can put controls on using the Horizontal/Vertical align parameters? Eg, Halign left valign top; halign right valign middle; etc etc.
2) Otherwise, when you say, "allow user change the location of controls by using indicator/cBot parameters", how do you mean? What parameters would you suggest? The Horizonal/Vertical align as in #1 above? Or something else?
3) And I noticed there appears to be no way to query the chart to see what controls are on the chart like we can query to find what "chart objects" are on the chart?
@firemyst
firemyst
22 Feb 2022, 12:42
RE: RE:
BJORNBERNAU said:
Yes. You don't need to do it in the indicator. The indicator always gets its own values. However, to save on resources, the robots don't load indicator data until they're actually needed. That's why you need to force it to load to tell the robot it's needed.
You do not care about "a" any more as I said previously.
"a" is just used as some place to force a value to be returned from the indicator.
Now that the indicator data has been loaded by the bot, you can go about getting any values you want from the indicator. Nothing else in the code needs to be changed unless you need data from other indicators.
@firemyst