Custom/semiformal indicator for rotation
Author: croyt
Creation Date: 6/14/2011 12:10 PM
profile picture

croyt

#1
While I tried to follow your examples (WeakStockRotation, Pgm Guide > Indicators > Custom Indicators), I've gone astray somewhere. The average RoC created inline (avroc) seems OK, but the semiformal version (avroc2) doesn't work. What am I overlooking?

General code critique welcome, too, if you have time.
CODE:
Please log in to see this code.
profile picture

Eugene

#2
The placement of the avgroc2 DataSeries ties it to the clicked symbol. Therefore it will always output the same value for any instrument.
profile picture

croyt

#3
Thanks, the avgroc2 DataSeries is just for a plot on the primary symbol. But the value is always zero, and I get no plot at all for that indicator. If I did it properly, I thought I could later assign a holder rank within the DataSetSymbols loop: holder.rank = avroc2[bar];

What's wrong with this picture?
profile picture

Eugene

#4
QUOTE:
But the value is always zero, and I get no plot at all for that indicator.

Absolutely right, because it's not programmed to assign any value to the DataSeries being returned.

Here's how it should be:
CODE:
Please log in to see this code.
profile picture

croyt

#5
Aha, now I see. Thanks for explaining.

Wouldn't it be safer, however, to allow seed time (longest period):
CODE:
Please log in to see this code.

Or does "FirstValidValue" handle that?

BtW: The time on this post is an hour off. Your site host doesn't seem to use EDST
profile picture

Eugene

#6
QUOTE:
Or does "FirstValidValue" handle that?

Not by default, but you can assign it any bar you think is appropriate (before using it in the loop, of course). (For example, like I doubled or tripled the FirstValidValue for unstable indicators (that e.g. use EMA or otherwise refer to their own previous readings) in Community Indicators. The standard indicator library is not using this approach.)

See also: GetTradingLoopStartBar.
profile picture

croyt

#7
OK, so far, thanks. Now I want a "Value" method for my informal AvgRoC indicator. One question, one problem:

I don't get the role of "base". Would you explain a bit, please?
CODE:
Please log in to see this code.


My "AvgRoc.Value" is clearly too naive
CODE:
Please log in to see this code.

and when called inside the trading loop, gets a missing reference error. What am I missing?
CODE:
Please log in to see this code.
profile picture

Eugene

#8
QUOTE:
I don't get the role of "base". Would you explain a bit, please?

Sure, check out the MSDN for base keyword.
QUOTE:
Now I want a "Value" method for my informal AvgRoC indicator.

Here you go:
CODE:
Please log in to see this code.

Keep in mind that calling the (optional) .Value method in a loop means unneccessary overhead. For example, your code above doesn't require the use of .Value.
profile picture

croyt

#9
Well, I'm trying to minimize overhead and simplify code at the same time, but I'm not sure I fully understand your point:
CODE:
Please log in to see this code.

"Unnecessary" in what sense? Can I somehow avoid building the complete Series? Is the alternative to which you refer simply:
CODE:
Please log in to see this code.

Or am I missing a cleaner, more compact way?

And finally ... why should .Value be "static"
profile picture

Eugene

#10
QUOTE:
Can I somehow avoid building the complete Series?

Generally you shouldn't, because with .Value in your code above 1) the calculation is done at every bar anyway and 2) the result is never cached.

Compare that to computing the DataSeries once with .Series and then Wealth-Lab caches it in Bars.Cache (formal indicators support caching as a rule).

For more details refer to

* QuickRef: the Bars object > the Cache Property
* API guide: Create an Indicator Library
profile picture

croyt

#11
Do I really need a .Series method, or can I do the cache check in the constructor? .Series seems to be an WLP 5.x legacy, and the Programming Guide > Series entry:
QUOTE:
Two methods are possible for returning an indicator's DataSeries; either method is equally acceptable.
Method 1:
Use the new operator to return an instance of the indicator derived from DataSeries. In addition to being more "professional", Method 1 allows you to provide a friendly string Description in the same call.

Method 2:
Pre-.NET legacy Wealth-Lab customers may find comfort in the static Series notation method to return a DataSeries type.

seems to recommend a direct "new" call and contradict the "Creating an Indicator Library" item:
QUOTE:

Supplying the description as an additional parameter to the constructor serves two roles:
1. It enforces that the same string is used in the Cache that is used in the indicator's
Description property.
2. It gives power users the flexibility to use the new operator to create indicator instances,
and provide their own descriptions. Indicators created using the new operator do not participate
in the caching mechanism.

Since my code loops through DataSetSymbols, I'd like to create an AvgRoC indicator only once for each symbol, then simply read the value at a particular Bar each time through the loop. What am I missing here, and what's the proper solution?
profile picture

Eugene

#12
QUOTE:
Do I really need a .Series method,

Yes.
QUOTE:
.Series seems to be an WLP 5.x legacy, and the Programming Guide > Series entry:

Misconception. Legacy is Version 3/4. Version 5 == 6 (.NET).
QUOTE:
Since my code loops through DataSetSymbols, I'd like to create an AvgRoC indicator only once for each symbol, then simply read the value at a particular Bar each time through the loop. What am I missing here, and what's the proper solution?

The solution is to follow the common design pattern, DataSetSymbols makes no difference. Implement the .Series method, the Bars.Cache (QuickRef it) will do the rest, ensuring that there's no overhead.
profile picture

croyt

#13
Thanks again for clarifying. I think you've saved me hours of frustration. During a backtest, I only need build and cache a DataSeries once for each symbol. Then, a .Value method would gain me nothing, since I only need the AvgRoC indicator values, already in cache, at specific bars when the strategy refreshes. Have I got the model right?

Two more questions:

The Programming Guide, cited in my 7/8 post, recommends
the "new" operator over a call to the "series" method.
Would that design fail to utilize some hidden machinery of
a "series" call, even when the constructor incorporates a
cache check? If so, where can I find an explanation of that
mechanism? Or ... the converse: Why NOT include a cache
check in the constructor?

If I overload the AvgRoC constructor to allow, for example,
both two- and three-component versions, I must also,
correspondingly, overload the .Series method, right?
profile picture

Eugene

#14
QUOTE:
Have I got the model right?

Yes. To be on the safe side, let me stress one thing that you already seem to realize: in your case, the indicator have to be built inside the DataSetSymbols loop - so not to end with a series built on the primary symbol.