Welcome to NexusFi: the best trading community on the planet, with over 150,000 members Sign Up Now for Free
Genuine reviews from real traders, not fake reviews from stealth vendors
Quality education from leading professional traders
We are a friendly, helpful, and positive community
We do not tolerate rude behavior, trolling, or vendors advertising in posts
We are here to help, just let us know what you need
You'll need to register in order to view the content of the threads and start contributing to our community. It's free for basic access, or support us by becoming an Elite Member -- see if you qualify for a discount below.
-- Big Mike, Site Administrator
(If you already have an account, login at the top of the page)
I've got a bug that I cannot sort out.. I am building some indicators and one of my primary goal is to ensure stationarity of the indicator values. This is to ensure handling those extreme values. To do this I am applying logic that both centers and scales the values between a range of +/- 50. The indicator is less important however the ability to normalize the data is critical.
What I have below is MC/Easy Language code for an Open/Close indicator that "ideally" is to be normalized between +/- 50. This logic is based on leveraging the InterQuartile Range (IQR).
In short, the final values are grouping around -50 and not cycling above/below 0 within the +50/-50 oscillations. The raw values look ok and nothing special, so I am thinking that the issue is perhaps with the calculation of the IQR itself. Everything else looks pretty vanilla as for syntax and use? Unless I should have some numericseries types there? but that would only be used in a function??
I am using a variation of the following normalization formula. y = 100 * (.5 * ((x-median)/(3rdQuartile-1stQuartile))-50.
And although I am using IQR I have tried a variation using standard scaling formula of y = 2((x-minx)/(maxx-minx))-1 to prove it out cycling between 1 and -1, but still no luck.
I appreciate your review and any tips.
I am on MC64bitv12 build 17002 with EasyLanguage
Slimmed down compiled/"working" code below:
// Note that '//' are for commenting and developer notes
// ver 999 - testing
// First are all the inputs
inputs:
ind_len(14), // indicator length
hist_len(100), // the historical length to be used for an entire historical dataset
med_len(40); // median length
variables:
oco_sum_o(0), // sum of opens
oco_sum_c(0), // sum of closes oco(0), // raw indicator
q1_oco(0), // 1st 25% quartile
q2_oco(0), // 2nd 50% quartile
q3_oco(0), // 3rd 75% quartile
nml_oco(0), // normalized oco value
cen_oco(0), // centered oco value
scl_oco(0), // scaled oco value
median_oco(0), // median oco value
iqr(0), // the inter-quartile range result q3-q1
num(0); // numerator
// calc the quartiles over the historical length
q1_oco = Quartile(1, oco[1], hist_len);
q2_oco = Quartile(2, oco[1], hist_len);
q3_oco = Quartile(3, oco[1], hist_len);
// Goal is to normalize the values between +/- 50 so as to force
// stationarity on the indicator values and create an oscillator around zero.
// Normalization calculation is to take the indicator value less the median and divide
// it by the IQR and compress between +/- 50.
num = ( oco - q2_oco );
iqr = ( q3_oco - q1_oco );
// handle divide by zero. ?Why doesn't EL/MC handle this explicitly?
if iqr = 0 then
iqr = iqr +.000000000001;
// full normalization including centering, scaling, and compression
nml_oco = 1 * (.5*((num)/(iqr))) - 50;
This is a code ( different language ) but similar in nature i use to normalize ATR to a ranking from 0 - 100 . You may be able to adapt it for your requirements
Thank you OzQuant for the tip. I will give that a go and see what it provides. I can see that it will consider all values within the lookback period and rank the value in relation to all the values.
Question to the group. One thing that I have not done and am considering. Is do I need to center the values within a high/low range of historical values first? Using ATR or other? I have not tried that, but I thought that is what the formula was doing anyway just with the Q2/IQR of the standard normal CDF setting the bounds?
ok answered my question.. (Still have to figure out why this is not oscillating like I expect...) but the formula is indeed handling both centering and scaling as part of the full normalization formula. The indicator values are 1st having the median subtracted which is to center it and 2nd then being divided by the IQR to scale.
v = value
r_min = range min
r_max = range max
t_min = target min
t_max = target max
scaled value = ((v-r_min)/(r_max-r_min))*(t_max-t_min)+t_min
The final working code..
// Note that '//' are for commenting and developer notes
// ver 002 - with scaling
// First are all the inputs
inputs:
ind_len(14), // indicator length
hist_len(100), // the historical length to be used for an entire historical dataset
med_len(40), // median length
slow_len(15), // slow ma length
fast_len(3); // fast ma length
variables:
oco_sum_o(0), // sum of opens
oco_sum_c(0), // sum of closes oco(0), // raw indicator
nml_oco(0), // normalized oco value
median_oco(0), // median oco value
atr_oco(0), // the atr of the indicator
h_oco(0), // high of oco over hist length
l_oco(0), // low of oco over hist length
num(0), // numerator
den(0), // denominator
ocobyatr(0), // result of oco / atr
t_min(-50), // scaling target min
t_max(50), // scaling target max
oco_qnt(0), // oco quotient
r_min(0), // range min
r_max(0), // range max
f_avg(0), // fast ma result
s_avg(0); // slow ma result
// take the raw oco and determine the H/L range over the historical length
h_oco = highestvalue(oco,hist_len);
l_oco = lowestvalue(oco,hist_len);
atr_oco = TrueRangeCustom(h_oco,l_oco,oco);
ocobyatr = oco/atr_oco;
// get the min and max of the indicator values
r_max = highestvalue(ocobyatr,hist_len);
r_min = lowestvalue(ocobyatr,hist_len);
// scaling and normalization
num = ( ocobyatr - Median(ocobyatr,hist_len) ) - (r_min);
den = (r_max - r_min);
if den = 0 then
den = den +.000000000001;
// new scaling formula
oco_qnt = num/den;
nml_oco =( oco_qnt * (t_max - t_min)) + t_min;
if nml_oco > 0 then
SetPlotColor(1, green)
else
SetPlotColor(1, red);
Best,
JZ
Mir1
Luzern, Switzerland
Posts: 1 since May 2023
Thanks Given: 0
Thanks Received: 0
Hey Joe
Would you PLS give me an example how can I use your normalized indicator for volatility exit or entry in signal like.....
If normalized value > 25 then sell next bar at market.
Or if normalized value > average normalized value then....
Thank you
Mir