- ago
My strategy compiles OK, but when entering the Execute section, I get the error "Object reference not set to an instance of an object." I suspect the issue is my declarations at the bottom of the execute section. See code
CODE:
      TimeSeries BuyDisp;       TimeSeries SellDisp;       TimeSeries OwnStock;       TimeSeries stop;       EMA ema_2;       EMA ema_5;       HMA hma_20;       HMA hma_4;       HMA hma_9;       HMA hma_16;       DecyclerOscillator do1;       StochRSI stochRsi;       TimeSeries HO;       TimeSeries HH;       TimeSeries HL;       TimeSeries HC;

I have placed all of the TimeSeries and indicator initial definitions in the Initialize section. What have I done wrong?
0
895
11 Replies

Reply

Bookmark

Sort
Glitch8
 ( 7.81% )
- ago
#1
In the template strategy code, we indicate the best place to put your declarations with a comment. They should all be declared OUTSIDE of any method. Create the instances in Initialize, and access them as you need to in Execute. Look at the many example strategies and build from there.
0
- ago
#2
I have all the Execute declarations below the //Comment line.
0
- ago
#3
What you may have is a "scoping" problem. In order to make an instance (or type) visible to both the Initialize{...} and Execute{...} block, they need to be declared in a block that's outside of both those blocks such as the Class{...} definition block. For example, you'll notice shared local variables are declared in the class definition block in all the WL7 strategy examples.

Look up "scoping" or "visibility" in you C# textbook for a better explanation.
0
Glitch8
 ( 7.81% )
- ago
#4
If we see your complete code I’m sure we’d be able to help. Right now there’s just not enough information to go on 🤷🏼‍♂️
0
- ago
#5
I sent the code to support.
Thank you
0
- ago
#6
Got your code. Although you did definea bunch of TimeSeries and other objects outside Initialize as it should be, in
CODE:
public override void Initialize(BarHistory bars)

you're again defining them like below which reassigns them to a new empty series, crossing out the work done by your logic inside Initialize.

Here's how you can fix it in Initialize:
CODE:
... //IndicatorBase hma_20 = new HMA(bars.Close, 140); hma_20 = HMA.Series(bars.Close, 140); //same for hma_4, hma_9, hma_16 stop = new TimeSeries(bars.DateTimes); //TimeSeries HO = bars.Open; HO = bars.Open; HH = bars.High; HL = bars.Low; HC = (bars.Open + bars.High + bars.Low + bars.Close) / 4;


Another issue is that nothing is assigned to hma20, stochRsi and do1 - these are empty series you're trying to access values from.
0
- ago
#7
So this is fundamentally a scoping problem with the C# language. Study the simplified example below to see if it makes good sense to you.
CODE:
namespace WealthScript {    public class MyStrategy : UserStrategyBase    {       public override void Initialize(BarHistory bars)       {          double x = 2;          double y = 3;          z = 4;       }       public override void Execute(BarHistory bars, int idx)       {          Print x; // x will be 1, _not_ 2 here          Print y; // y will be "instance not set" here, _not_ 3          Print z; // z will be 4 as expected       }       //declare private variables below       double x = 1;       double y;       double z;    } }
If the above example looks too complex to understand, crack your C# textbook open to the "scoping" section and study the simpler examples. When doing so, ask yourself, "Why do all modern computer languages use this architecture?"

For example, imagine if Programmer 1 wrote the class procedure and Programmer 2, who knows nothing about Programmer's 1 code, wrote the Initialize procedure. And Programmer 3 wrote the Execute code. In this case, you would want the compiler to recognize y as 3 in Initialize, and non-existent in Execute, which is what the compiler is doing since Programmer 3 knows nothing about Programmer's 2 local Initialize y variable usage.

And these scoping rules apply to all modern computer languages (Java, C, C++, C#, Python, etc). Get the big picture behind the language design and you'll find this easy and expected.
0
- ago
#8
Eugene,
I made the changes as you suggested. But still have the same problem. Here is the error message, maybe that may be a clue.

Execute Exception (APPS,199) Line 197 - Object reference not set to an instance of an Object.
at WealthScript1. MyStrategy.Execute(BarHistory bars, Int32 idx) in : Line 197
at Wealthlab. Backtest.UserStrategyExcecutor.ResetVisitor(List'1 Ist, DateTime dt)

Line 197 is just where it stops and is a debug line. That "ResetVisitor" is intriguing.
Thank you
0
- ago
#9
I just outlined the most evident changes as the script is big. Maybe there are some other declarations left to include that I overlooked.
0
- ago
#10
The declarations are what controls the scoping. You want to set the declarations such that your shared variables are scoped so that they're visible to both the class{}, Initialized{}, and Execute{] blocks--all three blocks--as is done with the "z" variable in my example in Post #7.

Variables x and y aren't scoped that way because of the way they are declared.
1
- ago
#11
Eugene,
Major progress today. If I want to get data back to the display area that is executed in the Execute section, then initialize TimeSeries only in the Initialize section. It took awhile to figure this out!
1

Reply

Bookmark

Sort