Login Page - Create Account

Support Board


Date/Time: Wed, 27 Nov 2024 08:29:06 +0000



[Programming Help] - Code help, using a string instead of a constant

View Count: 618

[2023-08-27 13:37:30]
j4ytr4der_ - Posts: 938
I'm modifying some open source code (from https://gcuserstudies.github.io/) but have run into a problem I've been unable to figure out how to solve. I'm sure this should be ridiculously simple but I've been at this for days and can't figure it out.

There is some code that evaluates a formula. It works fine for a single iteration, but I want it to execute in a (manual) loop of all the available inputs. This is a problem because the original loop uses a constant (
const char*
) and so the loop can't modify it each time. I've tried using an SCString instead but then the value of the formula gets mangled and doesn't appear to execute properly.

In abbreviated form, here's the code that "works" in the loop of inputs, but the value of the constant never changes once it's set the first time.



  ParseAndSetFormula = sc.IsFullRecalculation;

  const char* Formula = sc.Input[InputIndex].GetString(); // Grab the formula for the chosen input

  double FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, ParseAndSetFormula, Formula); // Evaluate the formula

  sc.Subgraph[InputIndex][BarIndex] = (float)FormulaOutput; // Return the formula result in a subgraph



I've tried changing
const char* Formula
to
SCString Formula
but it doesn't work. I've also tried just using
char
rather than
const char
but that won't even compile.

I know slightly more than nothing about C++ so I'm fairly sure I'm probably missing something really simple/obvious to someone who knows what they're doing. Can anyone point me in the right direction here?
[2023-08-27 15:18:48]
ondafringe - Posts: 286
I don't know enough to help you, other than to say:

I think this

char* formula;

creates a pointer called "formula" It doesn't create a variable called "formula"

and you can't assign a value to a pointer like this

const char* Formula = sc.Input[InputIndex].GetString();

like you would to a variable.

So you might want to do some digging into c++ pointers.
[2023-08-27 17:37:23]
User431178 - Posts: 543
and you can't assign a value to a pointer like this
Sorry, but that is not correct, look at what the return type is for GetString.


@j4ytr4der_

and so the loop can't modify it each time
That doesn't seem right either.
Is InputIndex the loop variable? I am assuming you are declaring Formula inside the loop
If Formula is decalred in loop then it goes out of scope at the end of each loop.

Please post additional code (or send via private message if you prefer).
Date Time Of Last Edit: 2023-08-27 19:53:31
[2023-08-27 18:26:09]
ondafringe - Posts: 286
Then explain so we can all learn something.

If


char* Formula


creates a pointer to a memory address holding char-type data, then if


sc.Input[InputIndex].GetString();

returns something like "&charvar" I can see how that would be valid, otherwise...

And to reference the value a pointer is pointing to, or pass that value as an argument like


double FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, ParseAndSetFormula, Formula);

don't you also have to preface it like so?

*Formula

Because

Formula

would only return the memory address the pointer is pointing to.
Date Time Of Last Edit: 2023-08-27 20:07:40
[2023-08-27 18:51:06]
j4ytr4der_ - Posts: 938
So yes, InputIndex is the loop counter. Formula is (attempting to be) defined at each repetition of the loop. I posted everything relevant I'm pretty sure, but here's the whole loop.


  bool ParseAndSetFormula = sc.IsFullRecalculation;

  for(int InputIndex = 1; InputIndex <= 16; InputIndex++) // Loop through each input
  {

    const char* Formula = sc.Input[InputIndex].GetString(); // Grab the formula for the chosen input

    for (int BarIndex = sc.UpdateStartIndex; BarIndex < sc.ArraySize; BarIndex++)
    {

      double FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, ParseAndSetFormula, Formula); // Evaluate the formula
      sc.Subgraph[InputIndex][BarIndex] = (float)FormulaOutput; // Return the formula result in a subgraph

    }
  }

Date Time Of Last Edit: 2023-08-27 19:11:58
[2023-08-27 20:12:42]
j4ytr4der_ - Posts: 938
Nope, using *Formula generates a CPU exception.
[2023-08-27 20:14:09]
j4ytr4der_ - Posts: 938
And again, the const char* DOES pick up the value of the input string as expected, but only the first time. Then it's there permanently since it's a constant, so every single subgraph after the first one parsed, gets the same result.
[2023-08-27 20:32:52]
ondafringe - Posts: 286
I'm looking at this link for pointers:
https://www.programiz.com/cpp-programming/pointers

But, yeah, this is pretty confusing stuff. lol

However, maybe the reason you are only getting the first formula is because you are trying to redeclare a const within the for loop.

I don't believe that is allowed, unless you first drop out of the for loop.

Have you tried declaring Formula like this, leaving const out:


char* Formula

I just looked at sc.EvaluateGivenAlertConditionFormulaAsDouble and it does show "const SCString& Formula" as the third argument, so the above probably won't work.
Date Time Of Last Edit: 2023-08-27 20:46:36
[2023-08-27 20:54:43]
User431178 - Posts: 543
And again, the const char* DOES pick up the value of the input string as expected, but only the first time.
As I said before, const char* goes out of scope at the end of each iteration of the main loop, 100% guaranteed it is reading the value of the other inputs.

The attached code works as expected (sligtly modified from what you posted), see also screenshot.
imagealert formula string.png / V - Attached On 2023-08-27 20:54:29 UTC - Size: 74.25 KB - 111 views
attachmentAlertString.cpp - Attached On 2023-08-27 20:54:38 UTC - Size: 1.6 KB - 161 views
[2023-08-27 21:10:15]
ondafringe - Posts: 286
As I said before, const char* goes out of scope at the end of each iteration of the main loop

Had no idea. Could have sworn it stayed in scope. Learned something new. :)

Still doesn't explain the pointer confusion because it doesn't seem to jive with what I read at that pointer link.
Date Time Of Last Edit: 2023-08-27 21:14:00
[2023-08-27 21:17:38]
j4ytr4der_ - Posts: 938
char* Formula won't compile. I'll try the posted code and see what's changed, thanks!
[2023-08-27 21:28:50]
j4ytr4der_ - Posts: 938
OK, the attached code works so I just need to work it into mine. Thanks, will post a link to it once it's working!
[2023-08-27 22:39:46]
j4ytr4der_ - Posts: 938
One question as this doesn't make sense to me. You made a small change to the final return of the value to a subgraph, that code is now:

sc.Subgraph[InputIndex][BarIndex] = (float)FormulaOutput * (InputIndex + 1); // Return the formula result in a subgraph

You added
* (InputIndex + 1)

What is the significance of that? Seems weird to me to multiply whatever the final result is, by the number of the current input plus 1.
[2023-08-28 01:12:46]
j4ytr4der_ - Posts: 938
Also I have to correct what I said before, the posted code does not work. It doesn't generate any errors, but it definitely doesn't work properly. I can enter the simple formula 1+1 and (after enabling display of name & values) the subgraph will flash to 2 for a moment, then back to zero. I can put in H, L, C, etc. and the same happens. It flashes the correct value for a moment, then goes to zero.
[2023-08-28 01:16:33]
j4ytr4der_ - Posts: 938
Actually on closer inspection, it's not even showing the correct values at all. Looking at ES where price is currently around 4430, and it's showing OHLC prices between 4000 and 17000. In fact each subgraph goes progressively higher, and if I fill all 4 with O H L and C, the values don't flash back to zero and I can see all of them.

https://snipboard.io/jwxJh8.jpg
Date Time Of Last Edit: 2023-08-28 01:18:06
[2023-08-28 08:47:20]
User431178 - Posts: 543
What is the significance of that? Seems weird to me to multiply whatever the final result is, by the number of the current input plus 1.

The purpose of that was to make the visual representation of each formula result easier to distinguish in the image that was attached, i.e. cleary show that each formula was there were being evaluated.

The demo image had 4 formula set, each yielding a true/false (1.0/0.0) output, rather than display all at 1.0, the results were adjusted to display the result of each at a different value.
Adding 1 to the input index is necessary as the inputs are indexed from 0.

Input 1: 1.0 * (0 + 1) = 1.0
Input 2: 1.0 * (1 + 1) = 2.0
etc...

Outside of what I wanted to demonstrate, the * (InputIndex + 1) part serves no purpose - remove it.
See attached image with offending code removed.
imageformula string ohlc.png / V - Attached On 2023-08-28 08:46:57 UTC - Size: 86.23 KB - 80 views
[2023-08-28 09:02:18]
User431178 - Posts: 543
The previously attached code served to demonstrate that what you were trying to do was possible, however it does not work correctly for live updating.
For live updating to work correctly, you will need to parse and set each formula again at each chart update. If the parse/set is not done, only the last set formula is used.
Updated code attached.

I should add that setting the formula at each update goes against the advice in the docs (inefficient), however I don't see an alternative.
Date Time Of Last Edit: 2023-08-28 09:02:46
attachmentAlertString.cpp - Attached On 2023-08-28 09:02:14 UTC - Size: 1.58 KB - 177 views
[2023-08-28 15:39:36]
j4ytr4der_ - Posts: 938
The problem I'm raising with your example code isn't about not updating live, it's that the initial values are completely nonsensical. Put something in all 4 formulas, specifically O, H, L, and C. I get values that make absolutely no sense.
[2023-08-28 16:00:03]
j4ytr4der_ - Posts: 938
OK now that I understand what that extra multiplication you added was about, removing it has corrected the behavior I was seeing. Thanks, I should be able to work with this.
[2023-08-28 16:29:00]
j4ytr4der_ - Posts: 938
I have it working for historical bars, but I can't get it to work for the current updating bar. As far as I understand it should be calculating correctly for all bars up to the last one but for some reason it isn't. Don't know what I'm missing.



#include "sierrachart.h"
SCDLLName("Multi Formula All Bars")
/*==================================================================================*/
SCSFExport scsf_TestProj(SCStudyInterfaceRef sc)
{
  sc.MaintainVolumeAtPriceData = 1;

  if (sc.SetDefaults)
  {
    sc.GraphName = "Multi Formula All Bars";
    sc.GraphRegion = 2;
    sc.AutoLoop = 0;
    sc.ValueFormat = VALUEFORMAT_INHERITED;
    sc.ScaleRangeType = SCALE_AUTO;
    sc.GlobalDisplayStudySubgraphsNameAndValue = 1;
    sc.DisplayStudyInputValues = 0;
    sc.HideDLLAndFunctionNames = 1;
    
    for (auto i = 0; i < 4; ++i)
    {
      sc.Input[i].Name.Format("s%d", i);
      sc.Input[i].SetString("");

      sc.Subgraph[i].Name.Format("s%d", 1);
      sc.Subgraph[i].DrawStyle = DRAWSTYLE_POINT;
      sc.Subgraph[i].LineWidth = 4;
    }

    return;
  }

  bool ParseAndSetFormula = sc.IsFullRecalculation;

  for (int InputIndex = 0; InputIndex < 4; InputIndex++) // Loop through each input
  {
    const char* Formula = sc.Input[InputIndex].GetString(); // Grab the formula for the chosen input

    for (int BarIndex = sc.UpdateStartIndex; BarIndex < sc.ArraySize; BarIndex++)
    {
      double FormulaOutput{ 0.0 };

      if (BarIndex == 0)
        FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, ParseAndSetFormula, Formula); // Evaluate the formula
      else
        FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, 0, ""); // Evaluate the formula

      sc.Subgraph[InputIndex][BarIndex] = (float)FormulaOutput; // Return the formula result in a subgraph
    }
  }
}


[2023-08-28 16:47:44]
User431178 - Posts: 543
I have it working for historical bars, but I can't get it to work for the current updating bar. As far as I understand it should be calculating correctly for all bars up to the last one but for some reason it isn't. Don't know what I'm missing.

Please see the second code example posted above.

this
bool ParseAndSetFormula = sc.IsFullRecalculation;
and

if (BarIndex == 0)
FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, ParseAndSetFormula, Formula); // Evaluate the formula
else
FormulaOutput = sc.EvaluateGivenAlertConditionFormulaAsDouble(BarIndex, 0, ""); // Evaluate the formula

Mean that the formula are parsed and set only during a full recalculation and only at bar index 0.
As you are cycling through various formula, you will need to parse and set each time, otherwise only the last set formula is applied.
[2023-08-28 17:00:13]
j4ytr4der_ - Posts: 938
Ah of course, I forgot about IsFullRecalculation. Got it now, thanks.

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account