Topics
Replies

firemyst
20 Apr 2022, 10:27

RE:

amusleh said:

Hi,

cTrader can load different number of data on your chart, there is no fixed number of bars.

You shouldn't rely on bar index numbers to be same across different machines, use bar open times instead.

Thank you for your response and confirmation.


@firemyst

firemyst
20 Apr 2022, 04:03 ( Updated at: 21 Dec 2023, 09:22 )

Any updates @Spotware?

Hello @Spotware / @Panagiotis / @Amusleh,

Following up as haven't seen a response in regards to this.

This is AUDCAD pair on Daily timeframe. First capture below is from my local laptop in UTC+8 time; second capture is from my VPS located in New York, but set to UTC + 8 time.

Since this is the DAILY timeframe and both charts are freshly loaded (eg, cTrader just started and no scrolling has been done), I would expect bar numbers and current indexes to be the same on both charts; however as you can see, they are way off. The indicator code used is in my original post.

This tells me that cTrader initially loads different amounts of chart data depending on what machine it's running on? Are you able to confirm this?

Otherwise, why would one daily chart for AUDCAD be up to bar number 1498 and the other be up to 1654 when both charts are freshly loaded on the same day in UTC time without any historical scrolling having been done?

Thank you.

 

Capture from local laptop:

Capture from VPS on same day a few minutes apart:


@firemyst

firemyst
05 Apr 2022, 09:09

> Hi, I would like to run this bot on different instances, but I couldnt do it. I tried label and symbol too.

 

What do you mean?

To run multiple instances of a bot, just add more "instances" under the bot and choose the symbol you want to run it against.

Example:

In teh above, one instance will run on EURUSD H1 timeframe, the other bot will run under the US30 symbol.


@firemyst

firemyst
05 Apr 2022, 09:04

Copy what?

Trades?

Code?

Set ups?

Charting templates?

Indicators?

EA's?

You'd probably get more answers if your request wasn't so vague.

 


@firemyst

firemyst
29 Mar 2022, 11:28

RE:

amusleh said:

Hi,

It does work, but it depends on the email service you are using, some services doesn't allow old SMTP authentication anymore like Gmail as it causes security issues.

I tested it on my own email server and it works fine.

cTrader automate API just provide a wrapper over .NET SMTP API to make it easier.

 

 

So it definitely works with gmail? I can set up a test gmail account, keep the same indicator code (except changing the email addresses as appropriate), and all should work "as is"?

Also, what do you mean by "old smtp authentication"? All the links I found, and posted in my original post, explain how to set up SMTP authentication with the parameters required by cTrader.

Thank you.


@firemyst

firemyst
20 Mar 2022, 05:02

Obviously it could depending on what your cBot does.

For instance - latency. Does your cBot continuously make big network calls sending and/or receiving huge amounts of data across the network? If so, then duh... obviously it could affect latency.

Your cBot could be 1Gig in size, but in terms of performance, size doesn't matter ;-) Again, it's what's inside the code that counts. If your cBot is heavily CPU intensive, then duh again... obviously it could affect performance depending on your VPS's configuration (Eg, do you have 2 cores? 4 cores? 8 cores?)

So without posting details of your cBot, there's no "one size fits all answer" to your question.


@firemyst

firemyst
18 Mar 2022, 09:00

RE:

amusleh said:

Hi,

The bar index should work fine, if it's not then it's a bug.

Can you tell me which broker you are using? which Renko chart? I will try to reproduce it.

 

Great. You have the code and screen capture above.

 

Broker is Pepperstone.

Renko chart is Re5.

Chart is NAS100. Date/time on the screen capture. But just in case, time in UTC + 8 is Mar 17th from 04:43 - 04:54

 

Thank you.


@firemyst

firemyst
12 Mar 2022, 12:29

No, it's not as of the last time I asked @Panagiotis.

Perhaps either he or someone from @Spotware can indicate if it's even in the timeline as a feature to be added to the API?

 

 


@firemyst

firemyst
10 Mar 2022, 15:01

THis happened with the latest driver update today from Intel. I've had to roll it back.

I've submitted a report to @Spotware through the ctrl-shift-alt-T so Spotware can confirm if it is another bug in the Intel driver or not.

It affects both my Pepperstone and IC Markets cTrader platforms.


@firemyst

firemyst
22 Feb 2022, 13:28 ( Updated at: 22 Feb 2022, 13:31 )

RE: RE: RE: RE:

BJORNBERNAU said:

Thank you! Well, I tried it. This does not change it. The code is now the following 

 

protected override void OnBar()
        {

            double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

            double b = S2.liq_ONE.Last(0);
            b = S2.liq_ONE.Last(0);


            if (!double.IsNaN(S2.sell_ONE.Last(0)) == true)
            {
                Print("SELL    ", Bars.Count, "      ", S2.sell_ONE);
            }

            if (!double.IsNaN(S2.liq_ONE.Last(0)) == true)
            {
                Print("LIQ    ", Bars.Count, "      ", S2.liq_ONE);
            }

        }

 

Resulting in this data stream - a block-wise procurement of SELL and LIQ. 

 

  double b = S2.liq_ONE.Last(0);
            b = S2.liq_ONE.Last(0);

WHY ARE YOU DOING THIS?! Not only are you assigning the same value to "b" twice, but you're also declaring a new variable, of which there's no need to declare a new "double b".

As I said, who cares if "a" gets overwritten with a new value?? -- you don't care about the value, and you never use it again. Don't take up extra computing resources by declaring another "double" that's not going to be used anywhere and that you're just assigning the same value to it twice in a row.

As for your overall print statements, it is working now. Your original issue was it kept printing "LastValue: NaN". It no longer does that. That issue is resolved.

If there's other logic issues in your indicator code, you'll have to figure those out or ask for help from others. :-)

 


@firemyst

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