Topics
Replies

firemyst
22 Feb 2022, 12:42

RE: RE:

BJORNBERNAU said:

So the "forcing" is actually happening in the Robot, not the Indicator?

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.

Then you have to convert the double.IsNaN(S2.liq_ONE[indicatorIndex]

into 

double.IsNaN(a) == false

is it or how does the Robot find "a"?

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

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:16

Nothing in the referenced link talks about or explains the concept of "lazy loading" of the indicators. There are numerous questions always popping up on the forums asking about this and people not being able to get values.


@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 

Join us on Telegram

HI @PanagiotisCharalampous

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 

Join us on Telegram and Facebook

PanagiotisCharalampous

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
30 Jan 2022, 13:24

You need to grant your cBot access.

Alter the line you have for [Robot ... ] to include the following:

[Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]

 

 


@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
28 Jan 2022, 07:43

RE:

PanagiotisCharalampous said:

Hi firemyst,

This will be introduced in 4.2.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Awesome! Thank you for the update!


@firemyst