Variable assignment in a function issue  [SOLVED]

Questions about MultiCharts and user contributed studies.
User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Variable assignment in a function issue

Postby JoshM » 31 Mar 2014

Hi,

I want to create a function that is repeatedly called by a signal on the same bar, but nonetheless only outputs data once per bar. For example, if the signal calls the function 9 times on a bar, it needs to do a certain action only once, and not nine times.

This is my example signal:

Code: Select all

[IntrabarOrderGeneration = true];

once cleardebug;

if (BarStatus(1) = 2) then begin

MyFunction(200, "Only on bar close tick");

end;

MyFunction(200, "Every tick");
I figured, if I evaluate the bar number and compare this with the bar number stored in a variable, a certain code block will only be executed once per bar, since after all there is only one time per bar that the bar number will be different.

So this is my example function:

Code: Select all

Inputs:
BarsToPrint(NumericSimple),
TextToPrint(StringSimple);

Variables:
printText(""),
IntraBarPersist PrevBarPrinted(0),
startBar(Symbol_Length - BarsToPrint),
bar_number(0);

bar_number = CurrentBar + MaxBarsBack;

if (bar_number < startBar) then
#return;

// Only on bar close and only if bar_number is different from PrevBarPrinted
if (BarStatus(1) = 2) and (bar_number <> PrevBarPrinted) then begin

printText = Text("BarClose: '", TextToPrint,
"' bar_number: ", NumToStr(bar_number, 0),
", prevBarPrinted: ", NumToStr(PrevBarPrinted, 0));

PrevBarPrinted = bar_number;

end else begin

printText = Text(Spaces(3), TextToPrint);

end;

Print(printText);
But this gives the following output:

Code: Select all

BarClose: 'Only on bar close tick' bar_number: 5289, prevBarPrinted: 5288
BarClose: 'Every tick' bar_number: 5289, prevBarPrinted: 5288
Every tick
Every tick
Every tick
Every tick
As you can see here, the function is called on bar number 5.289, but the `PrevBarPrinted` variable is only assigned the proper value after the second call.

In other words, the `bar_number: 5289, prevBarPrinted: 5288` output is only allowed to be printed once per bar. After all, if `PrevBarPrinted` is assigned the value of `bar_number`, this can only be true once (and not twice) per bar.

So the problem is likely to be located here:

Code: Select all

if (BarStatus(1) = 2) and (bar_number <> PrevBarPrinted) then begin

...

PrevBarPrinted = bar_number;

end
So I would expect the output to be like this:

Code: Select all

BarClose: 'Only on bar close tick' bar_number: 5289, prevBarPrinted: 5288
Every tick
Every tick
Every tick
Every tick
However, the output shows that this is clearly not the case, so something must be going wrong here. Do you might have an idea what can cause this?


Notes:
* Using `IntraBarPersist` or not did not affect this behaviour.
* I'm using MultiCharts64 Version 8.8 Release (Build 8967).
* The function is a Numeric Simple function.

User avatar
Henry MultiСharts
Posts: 9165
Joined: 25 Aug 2011
Has thanked: 1264 times
Been thanked: 2957 times

Re: Variable assignment in a function issue

Postby Henry MultiСharts » 02 Apr 2014

Hello Josh,

Please modify your signal the following way:

Code: Select all

[IntrabarOrderGeneration = true];

once cleardebug;

if (BarStatus(1) = 2) then

MyFunction(200, "Only on bar close tick");
else

MyFunction(200, "Every tick");

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Variable assignment in a function issue

Postby JoshM » 02 Apr 2014

Hello Josh,

Please modify your signal the following way:

Code: Select all

[IntrabarOrderGeneration = true];

once cleardebug;

if (BarStatus(1) = 2) then

MyFunction(200, "Only on bar close tick");
else

MyFunction(200, "Every tick");
Thanks Henry for thinking along, but that would only solve my example and not the underlying behaviour. In other words, that would not give me a versatile function that can called with different messages multiple times per bar.

For example, an if-then statement would not working in a situation like:

Code: Select all

if (BarStatus(1) = 2) then begin

MyFunction(200, "On bar close tick; evaluating strategy");

end;

if (myProfit < x) then
MyFunction(200, "Alert: profit below treshold");

if (MarketPosition(0) <> 0) then
MyFunction(200, "Evaluating open position");
In this case, the function can be called three times per bar. However, it should only do a certain action only once on that bar.
I want to create a function that is repeatedly called by a signal on the same bar, but nonetheless only outputs data once per bar. For example, if the signal calls the function 9 times on a bar, it needs to do a certain action only once, and not nine times.(....)
I'm inclined to believe that this cannot be done in MultiCharts, because the program seems to instantiate a function for every call in a signal/indicator. And these function objects do not seem to share the same member fields.

For example, using the same `MyFunction`, and the following example signal:

Code: Select all

[IntrabarOrderGeneration = true];

once cleardebug;

if (BarStatus(1) = 2) then begin

MyFunction(200, "Only on bar close tick");

end;

MyFunction(200, "Every tick");

if (Mod(CurrentBar, 2) = 0) then
MyFunction(200, "Even bar number");

MyFunction(200, "another message");
The output is:

Code: Select all

BarClose: 'Only on bar close tick' bar_number: 5365, prevBarPrinted: 5364
BarClose: 'Every tick' bar_number: 5365, prevBarPrinted: 5364
BarClose: 'another message' bar_number: 5365, prevBarPrinted: 5364
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
While I expect it to be:

Code: Select all

BarClose: 'Only on bar close tick' bar_number: 5365, prevBarPrinted: 5364
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Even bar number
another message
Every tick
Since after all, the following condition can only be true once for that bar:

Code: Select all

if (BarStatus(1) = 2) and (bar_number <> PrevBarPrinted) then begin

...

PrevBarPrinted = bar_number;

end

User avatar
JoshM
Posts: 2195
Joined: 20 May 2011
Location: The Netherlands
Has thanked: 1544 times
Been thanked: 1565 times
Contact:

Re: Variable assignment in a function issue  [SOLVED]

Postby JoshM » 02 Apr 2014

I came up with a workaround using a text array.

Disadvantages: more code overhead, more chance at making an array error (array index out of range error).
Advantages: it works.

Function:

Code: Select all

Inputs:
BarsToPrint(NumericSimple),
DataToPrint[MaxSize](StringArray);

Variables:
printText(""),
startBar(Symbol_Length - BarsToPrint),
IntraBarPersist PrevBarNumber(0),
bar_number(0), x(0);

bar_number = CurrentBar + MaxBarsBack + 1;

if (bar_number < startBar) then
#return;

for x = 0 to Array_GetMaxIndex(DataToPrint) begin

// Check for empty string
if (DataToPrint[x] <> "") then begin

if (x = 0) then begin

if (bar_number <> PrevBarNumber) then
printText = Text("This is the first time of this bar. ", DataToPrint[x], NewLine)
else
printText = Text(Spaces(3), "additional calls. Bar number: ", NumToStr(bar_number, 0),
", message: ", DataToPrint[x], NewLine);

PrevBarNumber = bar_number;

end

else if (x < Array_GetMaxIndex(DataToPrint)) then
printText = Text(printText, Spaces(3), "Additional calls. Bar number: ", NumToStr(bar_number, 0),
", message: ", DataToPrint[x], NewLine)

else
printText = Text(printText, Spaces(3), "Additional calls. Bar number: ", NumToStr(bar_number, 0),
", message: ", DataToPrint[x]);

end;
end;


Print(printText);
Example signal:

Code: Select all

[IntrabarOrderGeneration = true];

Array:
textArray[4]("");


once cleardebug;

if (BarStatus(1) = 2) then begin

textArray[0] = "Only on bar close tick";

end;

textArray[1] = "Every tick";


if (Mod(CurrentBar, 2) = 0) then
textArray[2] = "even bar number";


textArray[3] = "Another message on every tick";

textArray[4] = "And yet another message";

MyFunction(200, textArray);
Output:

Code: Select all

Additional calls. Bar number: 5369, message: Another message on every tick
Additional calls. Bar number: 5369, message: And yet another message
additional calls. Bar number: 5369, message: Only on bar close tick
Additional calls. Bar number: 5369, message: Every tick
Additional calls. Bar number: 5369, message: even bar number
Additional calls. Bar number: 5369, message: Another message on every tick
Additional calls. Bar number: 5369, message: And yet another message
This is the first time of this bar. Only on bar close tick
Additional calls. Bar number: 5370, message: Every tick
Additional calls. Bar number: 5370, message: even bar number
Additional calls. Bar number: 5370, message: Another message on every tick
Additional calls. Bar number: 5370, message: And yet another message
additional calls. Bar number: 5370, message: Only on bar close tick
Additional calls. Bar number: 5370, message: Every tick
Additional calls. Bar number: 5370, message: even bar number
Additional calls. Bar number: 5370, message: Another message on every tick
Additional calls. Bar number: 5370, message: And yet another message
additional calls. Bar number: 5370, message: Only on bar close tick
Additional calls. Bar number: 5370, message: Every tick
Additional calls. Bar number: 5370, message: even bar number

Learned from this topic:
Do not call a function more than once per tick, since this gives illogical and unexpected results.


Btw, I think that this topic showed a shortcoming or potential issue in MultiCharts: it is certainly imaginable that a user calls a function more than once per tick. It will probably be a good idea if a MC engineer can look into this.

User avatar
Henry MultiСharts
Posts: 9165
Joined: 25 Aug 2011
Has thanked: 1264 times
Been thanked: 2957 times

Re: Variable assignment in a function issue

Postby Henry MultiСharts » 04 Apr 2014

Here is a simpler workaround.
Attachments
test.pla
(4.5 KiB) Downloaded 398 times


Return to “MultiCharts”