Coffee
Will examine and test a rather silly idea
Let's set up some base rules first
- We have a constant moving average called the spine
- We measure the high and low distance to that spine
- We keep 2 averages going for those distances a fast and a slow
- Having in total 5 averages (with the spine)
That is a quick write up , here is the code :
#property version "1.00" #property indicator_chart_window #property indicator_buffers 10 #property indicator_plots 1 input int SpinePeriod=4;//Spine period input ENUM_APPLIED_PRICE SpinePrice=PRICE_MEDIAN;//Spine price input int SlowsPeriod=200;//Slow periods input int FastsPeriod=7;//Fast periods input string noteA="STYLING";//------------------------- input color SpineColor=clrWhite;//Spine Color input ENUM_LINE_STYLE SpineStyle=STYLE_SOLID;//Spine Style input int SpineWidth=1;//Spine Width //--- indicator buffers double Spine[],spinePeriod[]; double DeltaHighToSpine[],DeltaLowToSpine[]; double SlowHighToSpineAvg[],SlowLowToSpineAvg[],SlowPeriods[]; double FastHighToSpineAvg[],FastLowToSpineAvg[],FastPeriods[]; bool RatesSeries=false; double FullSpine=0.0,FullSlow=0.0,FullFast=0.0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping int co=0; RatesSeries=false; SetIndexBuffer(co,Spine,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_LINE); PlotIndexSetInteger(co,PLOT_LINE_COLOR,SpineColor); PlotIndexSetInteger(co,PLOT_LINE_STYLE,SpineStyle); PlotIndexSetInteger(co,PLOT_LINE_WIDTH,SpineWidth); co++; SetIndexBuffer(co,spinePeriod,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,DeltaHighToSpine,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,DeltaLowToSpine,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,SlowHighToSpineAvg,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,SlowLowToSpineAvg,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,SlowPeriods,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,FastHighToSpineAvg,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,FastLowToSpineAvg,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); co++; SetIndexBuffer(co,FastPeriods,INDICATOR_DATA); PlotIndexSetInteger(co,PLOT_DRAW_TYPE,DRAW_NONE); FullSpine=SpinePeriod; FullFast=FastsPeriod; FullSlow=SlowsPeriod; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(SymbolIsSynchronized(_Symbol)){ // //first load reset buffers int from=prev_calculated+1,to=rates_total; if(prev_calculated==0){ //do a reset if(ArrayIsSeries(open)){RatesSeries=true;} ArrayFill(Spine,0,ArraySize(Spine),0.0); ArrayFill(spinePeriod,0,ArraySize(spinePeriod),0.0); ArrayFill(DeltaHighToSpine,0,ArraySize(DeltaHighToSpine),0.0); ArrayFill(DeltaLowToSpine,0,ArraySize(DeltaLowToSpine),0.0); ArrayFill(SlowHighToSpineAvg,0,ArraySize(SlowHighToSpineAvg),0.0); ArrayFill(SlowLowToSpineAvg,0,ArraySize(SlowLowToSpineAvg),0.0); ArrayFill(SlowPeriods,0,ArraySize(SlowPeriods),0.0); ArrayFill(FastHighToSpineAvg,0,ArraySize(FastHighToSpineAvg),0.0); ArrayFill(FastLowToSpineAvg,0,ArraySize(FastLowToSpineAvg),0.0); ArrayFill(FastPeriods,0,ArraySize(FastPeriods),0.0); } //loop for(int i=from;i<rates_total;i++){ int j=i; if(!RatesSeries){j=rates_total-i-1;} //spine spinePeriod[i]=spinePeriod[i-1]; Spine[i]=Spine[i-1]; add_to_rolling_average(get_prices(open[j],high[j],low[j],close[j],SpinePrice),spinePeriod[i],SpinePeriod,Spine[i]); /* if spine's period is full then start collecting deltas */ //if spine period is full if(spinePeriod[i]==FullSpine){ DeltaHighToSpine[i]=MathAbs(high[j]-Spine[i]); DeltaLowToSpine[i]=MathAbs(low[j]-Spine[i]); //if we collect deltas we can start rolling avg deltas //propagation of rolling averages SlowHighToSpineAvg[i]=SlowHighToSpineAvg[i-1]; SlowLowToSpineAvg[i]=SlowLowToSpineAvg[i-1]; SlowPeriods[i]=SlowPeriods[i-1]; FastHighToSpineAvg[i]=FastHighToSpineAvg[i-1]; FastLowToSpineAvg[i]=FastLowToSpineAvg[i-1]; FastPeriods[i]=FastPeriods[i-1]; //Slows add_to_rolling_average(DeltaHighToSpine[i],SlowPeriods[i],SlowsPeriod,SlowHighToSpineAvg[i]); SlowPeriods[i]=SlowPeriods[i-1]; add_to_rolling_average(DeltaLowToSpine[i],SlowPeriods[i],SlowsPeriod,SlowLowToSpineAvg[i]); //Fasts add_to_rolling_average(DeltaHighToSpine[i],FastPeriods[i],FastsPeriod,FastHighToSpineAvg[i]); FastPeriods[i]=FastPeriods[i-1]; add_to_rolling_average(DeltaLowToSpine[i],FastPeriods[i],FastsPeriod,FastLowToSpineAvg[i]); } //if spine period is full ends here } //loop // return(rates_total); }return(0); } //+------------------------------------------------------------------+ double get_prices(const double open,const double high,const double low,const double close,ENUM_APPLIED_PRICE applied){ double price=0.0; if(applied==PRICE_CLOSE){price=close;} else if(applied==PRICE_HIGH){price=high;} else if(applied==PRICE_LOW){price=low;} else if(applied==PRICE_OPEN){price=open;} else if(applied==PRICE_MEDIAN){price=NormalizeDouble((high+low)/2.00,_Digits);} else if(applied==PRICE_TYPICAL){price=NormalizeDouble((high+low+close)/3.00,_Digits);} else if(applied==PRICE_WEIGHTED){price=NormalizeDouble((high+low+close+close)/4.00,_Digits);} return(price); } void add_to_rolling_average(double data,double &_total,int max,double &avg){ _total+=1.0; int t=(int)MathRound(_total); //if its beyond the max if(t>max){ //remove a portion add a new one avg=avg-(avg/((double)max))+(data/((double)max)); _total=max; } //if it just arrived else if(t==max){ avg+=data; avg/=((double)max); } //if its below else{ avg+=data; } }
We have the spine average , rolling .
When we have enough spine periods we start collecting spine deltas.
We also rolling average them
Now here is the weird attempt.
We want to create an index which when added on the spine it comes as close as possible to the actual high prices.
We will call this highGuess . Same for the lows , lowGuess.
So let's establish more rules :
- we start "optimizing" when we have full periods on everything
We are not interested in what happened each yesterday with yesterdays spine and yesterdays guesses , like analysts are . Nonono , we want
the yesterdays spine to project todays high and lows , and if it fails we won't hide it! So rule 2
-
we take previous bar's spine and previous bars rollings to project todays high and low
Now let's introduce more weirdness . We have fasts and slows right ?
If we have a plot that is a composite of the slow and fast and a toggle variable that adjusts the weights of how much fast and how much slow the
plot is we can get a fluctuating average , won't be accurate , but , won't be slow either (in crunch time).
So let's call that X . If X is the weight , the % , the amount of Fasts in the new plot then 1.00 - X is the % , the amount of Slows in the Plot.
That is very handy as this is one unknown !
So , if we have :
- a completed bar
- with a previous bar that has all rollings available
- we know the previous to it spine level
- we know its high and low
- we don't know what X is (or what X should have been)
And this is the weird part , we will use the X of the knowns as the "toggle" for the unknowns and , we will plot the guesses accordingly (including our errors).
After that we could go ahead and also rolling average the X! but one weirdness at a time .
So okay , we want X , how do we get it ?
and for the Lows
If there's a mistake let me know .
So let's code it and see what happens.
On first glance its volatile , both guesses .
(white=spine , blue=guess high, red = guess low)
So what can we do? We can try adding a rolling average to the x coefficients as well.
hmm not much better xD . Anyway that was fun.
attached is the source code.
--EDITS-----
But hang on , we are getting high projections that are below the spine .
Why ? because the projection is based on the previous spine and we will only know the current spine once the bar concludes .
There is no point in projecting on the spine as it evolves , we want a clear projection at the time of bar opening that says
high is here , low is here . We want to trade it not brag about it being right yesterday .
However , if we place ourselves at the time of a bar's opening , we do have the open price .! right ?
So , version 2 can be using the open price for both testing and projecting instead of the spine .
Let's see how it does.
Not much different , but i realized that we have an issue anyway.
the Xs are not bound between 0 and 1 !
i'll have to come up with something better there.
Anyway attaching the version with opens as well.
Will update when i find a solution