Indicators: 3D Spiral Quotes

 

3D Spiral Quotes:

Demonstration of Canvas's capabilities using 3D spiral quotes as an example.

3D Spiral Quotes

Author: Nikolai Semko

 
Automated-Trading :

3D Spiral Quotes :

Author: Nikolai Semko

Just magic. !!!

And if you add a polar grid to the axis, and the ability to change the scale, up to almost straight "parallels," we get a smooth transition to the traditional schedule.

 

Version 2.0

Added the ability to change the period (the number of bars in one circle). To do this, just click the left mouse button.


 

 

This is so nice 

I tried a rate of change adaptation . I butchered the code though .

//+------------------------------------------------------------------+
//|                                                     3DSpiral.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                         https://www.mql5.com/en/users/nikolay7ko |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, Nikolay Semko"
#property link      "https://www.mql5.com/ru/users/nikolay7ko"
#property link      "SemkoNV@bk.ru"
#property version   "2.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   0
#include "iCanvas_CB.mqh";

input int N = 200; // Maximum circles

double cl[];
int Size;
double max, min;
double _r;
int _per=0,per=0;
double K;
bool rotate = true;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit() {
   ChartSetInteger(0,CHART_SHOW,false);
   SetIndexBuffer(0,cl);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_NONE);
   _r=_Height/2-7;
   _per=int(2*M_PI*_r);
   per = _per;
   K=100*_Height;
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   ChartSetInteger(0,CHART_SHOW,true);
}
//+------------------------------------------------------------------+
//| 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[]) {
   int d=rates_total-prev_calculated;
   if (d>1 || d<0 || Size<10) {
      
      //Size=ArrayCopy(cl,close,0,rates_total-per*N,per*N);
        int from=rates_total-2;
        int to=1;
        if(to<1){to=1;}
        Size=0;
        for(int i=from;i>=to;i--){
        Size++;
        cl[Size-1]=(close[i]-close[i+1])/close[i+1];
        if(i==from){min=cl[Size-1];max=cl[Size-1];}else{
        if(cl[Size-1]>max){max=cl[Size-1];}
        if(cl[Size-1]<min){min=cl[Size-1];}
        }
        }

   } else {
      if (d==1) Draw();
   }
   return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
   if (id==CHARTEVENT_CLICK) rotate = !rotate;
   if (id==CHARTEVENT_MOUSE_MOVE)  {
      if (!rotate) per = int((1+5.0*_MouseX/_Width)*_per);
      Draw();
   }
  
}
//+------------------------------------------------------------------+
void Draw() {
   static int mx = 0,my =0;
   ulong t=GetMicrosecondCount();
   int X=_Width/2;
   int Y=_Height/2-5;
   Canvas.Erase(0xFF000000);
   Print("Range : "+(max-min));
   if (max-min<=0) return;
   int nn=0;
   double c=0;
   if (rotate) {
      mx = _MouseX;
      my = _MouseY;
   }
   int _a=(X   - mx + 5*per);
   int _b=(Y+5 - my + 5*per);
  
   for (int i=0; i<Size; i++) {
      double r = _r*(0.3+0.7*(cl[i]-min)/(max-min));
      int a = i;
      double cc=cos(a*2*M_PI/per);
      if (c<0 && cc>=0) nn++;
      c=cc;
      double z =r -r*2*double(i)/Size;
      double x = c*r;
      double y = sin(a*2*M_PI/per)*r;
      //double R=sqrt(x*x+y*y+z*z);
      double x1=x*cos(_a*2*M_PI/per)+z*sin(_a*2*M_PI/per);
      double z1=-x*sin(_a*2*M_PI/per)+z*cos(_a*2*M_PI/per);
      double y1=y*cos(_b*2*M_PI/per)+z1*sin(_b*2*M_PI/per);
      double z2=-y*sin(_b*2*M_PI/per)+z1*cos(_b*2*M_PI/per);
      z2=z2+_r;
      x=X+K*x1/(z2+K);
      y=Y+K*y1/(z2+K);
      _PixelSet((int)x,(int)y,Canvas.Grad(double(i)/Size));
   }
   t=GetMicrosecondCount()-t;
   _CommXY(20,30,_Symbol);
   _Comment("Total "+string(nn)+" Circles");
   _Comment("Circle period = " + string(per)+" bars");
   _Comment("Runtime = "+string (t) +" mks");
   Canvas.Update();
}
 
Lorentzos Roussos #:

This is so nice 

I tried a rate of change adaptation . I butchered the code though .


so it will be more correct and even more so you can look good in the tester (only set the Maximum circles smaller)

//+------------------------------------------------------------------+
//|                                                     3DSpiral.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                         https://www.mql5.com/en/users/nikolay7ko |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, Nikolay Semko"
#property link      "https://www.mql5.com/ru/users/nikolay7ko"
#property link      "SemkoNV@bk.ru"
#property version   "2.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   0
#include <Canvas\iCanvas_CB.mqh> //https://www.mql5.com/ru/code/22164

input int N = 200; // Maximum circles

double cl[];
int Size;
double max=-DBL_MAX, min=DBL_MAX;
double _r;
int _per=0,per=0;
double K;
bool rotate = true;
int startPos = 0;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit() {
   ChartSetInteger(0,CHART_SHOW,false);
   SetIndexBuffer(0,cl);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_NONE);
   _r=_Height/2-7;
   _per=int(2*M_PI*_r);
   per = _per;
   K=100*_Height;
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   ChartSetInteger(0,CHART_SHOW,true);
}
//+------------------------------------------------------------------+
//| 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[]) {
   int d=rates_total-prev_calculated;
   Size = rates_total;
   if (prev_calculated == 0 && rates_total>per*N) startPos = rates_total-per*N;
   if (d>0) {
        int from = prev_calculated>0?prev_calculated-1:0;
        for(int i=from+1;i<Size;i++){

         cl[i]=(close[i]-close[i-1])/close[i];
         //cl[i]=close[i];
         if (i >= startPos+1) {
            if(cl[i]>max) max=cl[i];
            if(cl[i]<min) min=cl[i];
         }
        }
   } else {
      cl[Size-1]=(close[Size-1]-close[Size-2])/close[Size-2];
   }
   Draw();
   return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
   if (id==CHARTEVENT_CLICK) rotate = !rotate;
   if (id==CHARTEVENT_MOUSE_MOVE)  {
      if (!rotate) per = int((1+5.0*_MouseX/_Width)*_per);
      Draw();
   }
  
}
//+------------------------------------------------------------------+
void Draw() {
   static uint last = 0;
   static int mx = 0,my =0;
   uint cur = GetTickCount();
   if (cur-last<30) return;
   last = cur;
   ulong t=GetMicrosecondCount();
   int X=_Width/2;
   int Y=_Height/2-5;
   Canvas.Erase(0x00FFFFFF);
   if (max-min<=0) return;
   int nn=0;
   double c=0;
   if (rotate) {
      mx = _MouseX;
      my = _MouseY;
   }
   int _a=(X   - mx + 5*per);
   int _b=(Y+5 - my + 5*per);
  
   for (int i=startPos,j=0; i<Size; i++,j++) {
      double r = _r*(0.3+0.7*(cl[i]-min)/(max-min));
      double cc=cos(j*2*M_PI/per);
      if (c<0 && cc>=0) nn++;
      c=cc;
      double z =r -r*2*double(j)/(Size-startPos);
      double x = c*r;
      double y = sin(j*2*M_PI/per)*r;
      //double R=sqrt(x*x+y*y+z*z);
      double x1=x*cos(_a*2*M_PI/per)+z*sin(_a*2*M_PI/per);
      double z1=-x*sin(_a*2*M_PI/per)+z*cos(_a*2*M_PI/per);
      double y1=y*cos(_b*2*M_PI/per)+z1*sin(_b*2*M_PI/per);
      double z2=-y*sin(_b*2*M_PI/per)+z1*cos(_b*2*M_PI/per);
      z2=z2+_r;
      x=X+K*x1/(z2+K);
      y=Y+K*y1/(z2+K);
      _PixelSet((int)x,(int)y,Canvas.Grad(double(i-startPos)/(Size-startPos)));
   }
   t=GetMicrosecondCount()-t;
   _CommXY(20,30,_Symbol);
   _Comment("Total "+string(nn)+" Circles");
   _Comment("Circle period = " + string(per)+" bars");
   _Comment("Runtime = "+string (t) +" mks");
   _Comment("Max : "+string(max));
   _Comment("Min : "+string(min));   
   Canvas.Update();
}



 

Nice thanks .

remember these ?

what if instead of controlling the period you were moving the rings to find alignments in change (visually)?

 
Lorentzos Roussos #:

Nice thanks .

remember these ?

what if instead of controlling the period you were moving the rings to find alignments in change (visually)?

it is probably easier to change the period not in bars, but in time.  hour, 12 hours, day, week, month, year
 
Lorentzos Roussos #: remember these ?

I still have one! 😅

 
Fernando Carreiro #:

I still have one! 😅

😂

Nikolai Semko #:
it is probably easier to change the period not in bars, but in time.  hour, 12 hours, day, week, month, year

I mean in theory , with a lot of quotes , if you "twist" , or , "squeeze" the display aren't you "viewing it from a different vantage point on a hyperdimensional space" ?

Im bad in math to explain this . So imagine you have 3 filled circles on 3 canvases stacked on top of each other . 1 circle per canvas . 

The circles vary in opacity based on the angle . So you design the circle and as the angle progresses you increase opacity .

Each circle has a different color 

If you place controls for each canvas (not circle) translation , scale , and rotation , there will be points that you are looking through and you are seeing a "different" "slice" of that domain.

 
Lorentzos Roussos #:

😂

I mean in theory , with a lot of quotes , if you "twist" , or , "squeeze" the display aren't you "viewing it from a different vantage point on a hyperdimensional space" ?

Im bad in math to explain this . So imagine you have 3 filled circles on 3 canvases stacked on top of each other . 1 circle per canvas . 

The circles vary in opacity based on the angle . So you design the circle and as the angle progresses you increase opacity .

Each circle has a different color 

If you place controls for each canvas (not circle) translation , scale , and rotation , there will be points that you are looking through and you are seeing a "different" "slice" of that domain.

Yes, a lot of things can be done, if there is time and desire. 😉

 
Nikolai Semko #:

Yes, a lot of things can be done, if there is time and desire. 😉

Ah yes . Time , what a beautiful thing