- ago
Over the past few weeks, I've been reading through the complete Wealth-Lab C-Sharp Coding Quick-Ref and have been looking at all the code examples in detail. Up front, a big compliment on how this is set up. It's very helpful in many places.
There are a few questions about some functions:

Corr and IsGapUp:
How exactly is the correlation coefficient and the GapUp calculated? Is there a formula available?

BarHistory.UserData:
I read that it is also possible to store more than one value? Is there an example in which form this can be done?

Thanks!
0
1,098
Solved
11 Replies

Reply

Bookmark

Sort
Glitch8
 ( 12.08% )
- ago
#1
It uses this method internally:

CODE:
public static double ComputeCoeff(List<double> values1, List<double> values2) { try { if (values1.Count != values2.Count) throw new ArgumentException("values must be the same length"); var avg1 = values1.Average(); var avg2 = values2.Average(); var sum1 = values1.Zip(values2, (x1, y1) => (x1 - avg1) * (y1 - avg2)).Sum(); var sumSqr1 = values1.Sum(x => Math.Pow((x - avg1), 2.0)); var sumSqr2 = values2.Sum(y => Math.Pow((y - avg2), 2.0)); var result = sum1 / Math.Sqrt(sumSqr1 * sumSqr2); return result; } catch { return Double.NaN; } }


UserData can contain any object, and a class can contain any number of properties, etc. That's what this means. Also consider using the Cache if you want to store multiple items in a BarHistory or TimeSeries.
0
Best Answer
- ago
#2
QUOTE:
BarHistory.UserData:
I read that it is also possible to store more than one value? Is there an example in which form this can be done?
Sure it's possible, you just have to cast to object when storing and then unbox to the real type when querying the UserData. Example below uses a custom Tuple but of course it could be anything:

CODE:
//create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          Tuple<string, double> t = new Tuple<string, double>(bars.Symbol, bars.Close[bars.Close.Count -1]);          bars.UserData = (Object)t;          WriteToDebugLog( (Tuple<string, double>)bars.UserData );          }
0
- ago
#3
QUOTE:
... and then unbox to the real type ...
And non-programmers won't know what boxing and unboxing are.

So in the example (reproduced below), UserData is holding a reference (i.e. memory pointer) to the object. When that happens, the compiler looses track on what that datatype (A Tuple in this example.) is that reference is pointing to. But that's not a problem because ...
CODE:
bars.UserData = (Object)t; //compiler looses track of the object's type when saving the reference pointer
... when you retrieve the object, you're going to cast () it back to the original datatype it was since the compiler has forgotten the datatype during the referencing process.
CODE:
Tuple<string, double> rtnObject = (Tuple<string, double>)bars.UserData; //cast reestablishes the datatype of the reference string argument1 = rtnObject.Item1; double argument2 = rtnObject.Item2;
Now rtnObject is cast back to the original datatype it had.

This example employs a Tuple. I would have employed an object defined by a "struct" instead, but either can work. If I wanted to point to a couple arrays or TimeSeries, I would use a struct construct.
0
Glitch8
 ( 12.08% )
- ago
#4
unboxing will only occur if you store a "primitive" type in UserData, like an int, double, etc. Then .NET has to box it into an Object type when storing it, and unbox it again when casting it back to the int, double, etc.

If you're storing object references, there's no boxing/unboxing going on.

I do remember that from the chapter on boxing/unboxing in my old C# book from 15 years ago :D
0
- ago
#5
What would be the proper syntax to pack two (or more) indicators into a UserData to later sort on Index1, then Index2 etc. - something like code below, but I am looking for the correct syntax packing values into UserData and then unpacking them inline for Sort operation:

CODE:
      public override void PreExecute(DateTime dt, List<BarHistory> participants)       {          //store the symbols' AvgROC value in their BarHistory instances          foreach (BarHistory bh in participants)          {             TimeSeries symbolRoc = (TimeSeries)bh.Cache[seriesKey];             int idx = GetCurrentIndex(bh); //this returns the index of the BarHistory for the bar currently being processed             double rocVal = symbolRoc[idx];             double atrpVal = symbolATRP[idx];             bh.UserData = ????; //save the current AvgROC and ATRP values along with the BarHistory instance          }          //sort the participants by AvgROC value (highest to lowest) then by ATRP value          participants.Sort((a, b) => b.UserData.rocVal == a.UserData.rocVal ?           b.UserData.atrpVal.CompareTo(a.UserData.atrpVal) : b.UserData.rocVal.CompareTo(a.UserData.rocVal));
0
- ago
#6
Have you seen posts #2 and #3 ??
0
Cone8
 ( 28.25% )
- ago
#7
I don't know what the objective of the multi-sort would be? Since there will be almost never be two values that are equal in the first sort, what's the purpose of the second sort? If you had a formula to combine the two values in some order of precedence and then sorted on that, it would make sense to me.

Maybe using a string in the Tuple instead of another value was confusing, and this helps?

CODE:
namespace WealthScript123 { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          ROC roc = ROC.Series(bars.Close, 10);          ATRP atrp = ATRP.Series(bars, 5);                    int idx = bars.Count - 1;          Tuple<double, double, double> t = new Tuple<double, double, double>(bars.Close[idx], roc[idx], atrp[idx]);          bars.UserData = (Object)t;          WriteToDebugLog( (Tuple<double, double, double>)bars.UserData);       }
0
- ago
#8
Of course you can pass several objects with UserData if you define them in a "struct" or tuple container (i.e. you "box" them); either works. Google "boxing and unboxing in c#".

CODE:
foreach (BarHistory bh in participants) { TimeSeries symbolRoc = (TimeSeries)bh.Cache[seriesKey]; int idx = GetCurrentIndex(bh); //this returns the index of the BarHistory for the bar currently being processed double rocVal = symbolRoc[idx]; double atrpVal = symbolATRP[idx]; bh.UserData = ????; //save the current AvgROC and ATRP values along with the BarHistory instance }
You're missing the line that pulls symbolATRP out of cache as well. Be sure to include that too.

Eventually you need to combine both symbolRoc and symbolATRP into a single merit-metric TimeSeries. Why not do that in Initialize{} in the first place so you only have one composite merit metric (as a TimeSeries) for PreExecute and UserData to handle? In other words, do the merit metric consolidation in Initialize{} instead of PreExecute{}. (And if you cache the consolidated merit metric TimeSeries in Initialize{}, then you "might not" need to cache the symbolRoc and symbolATRP for later.)

On the consolidation of symbolRoc and symbolATRP into a single merit metric, the "standard approach" is to take their product, but this is only valid if the value for both is greater than or equal to +1.00. You could also add them. In general:

consolidation = coeff1*symbolRoc + coeff2*symbolATRP + coeff3*symbolRoc*symbolATRP

And a stat package can compute a "P" (i.e. probability) for each individual term so you know which of these terms should be included (is significant) in the general merit-metric solution.
1
- ago
#9
Thank you @superticker and @Cone - it seems that sorting by a single combined metric is an approach that makes more sense. I guess that for some of the metrics I would need to normalize their ranges first and then apply appropriate coefficients, but that is doable.

What happens if I cannot cache one of the metrics in Initialize phase (for example if it is driven by trading action and updated dynamically in Execute block)?

Would it only impact the performance or would it produce incorrect results?
0
- ago
#10
QUOTE:
What happens if I cannot cache one of the metrics in Initialize phase (for example if it is driven by trading action and updated dynamically in Execute block)?

Is the assumption here that you're trading 10s of millions of dollars on a trade such that it will affect market prices? If the answer is "no", and market prices won't be affected by your trading action, then there isn't any reason to base a merit metric on your trades in the first place. I would proceed as if market prices will not be affected by your trading activity. Do everything (merit metric consolidation) in Initialize.

In contrast, if you are moving 10s of millions of dollars on a trade such that market prices will be affected, then you should employ some enterprise software that will automatically break that trade down into many smaller "dark lots" and trade those smaller lots over time like all the other big boys do.

And I would avoid trading GameStop. Too dangerous.

QUOTE:
Would it only impact the performance

Boxing (in Execute) and unboxing (in PreExecute) would take a small performance hit. But I would never get the merit metric involved in past trades.

If you want to snoop past trading history, do it only in Execute. Let Execute examine the Position attributes to make decisions based on trade history. Read up on the "GetPositons" property so you can gather a List<Position> collection to examine them. There are also LastPosition, LastOpenPosition, OpenPositions, etc. properties that may interest you.
1
- ago
#11
Offtopic discussion moved to:
https://www.wealth-lab.com/Discussion/Avoid-wash-sales-7060
1

Reply

Bookmark

Sort