InvChanel

This script is a technical analysis tool designed to visualize the relationship between two different currency pairs (for example, EURUSD and GBPUSD) by calculating their relative price movements. Instead of looking at one market in isolation, it measures how one pair moves in proportion to the other, creating a unique mathematical correlation.

Core Logic and Functionality

1. Relative Price Calculation The tool begins by synchronizing the data from two different currency pairs. It looks at the closing price of both pairs at each point in time and divides the price of the first pair by the second. This generates a new data stream that represents the "ratio" between the two assets, allowing you to see if they are moving in tandem, diverging, or maintaining a specific consistent distance from one another.

2. Statistical Regression Analysis The heart of this script is a mathematical process called "Linear Regression." The tool analyzes the history of the ratio calculated above and attempts to find the "line of best fit." In simple terms, it calculates a straight line that most accurately represents the overall trend of the relationship between the two pairs over a specific period.

3. Dynamic Channel Generation Once the main trend line (the regression line) is established, the script automatically calculates a "Maximum Deviation." It looks back at the historical data to find the furthest point where the price ratio strayed from the center line. Using this maximum distance, it draws an upper and lower boundary around the trend line. This creates a visual "channel" or corridor.

Visual Elements on the Chart

The script provides several visual cues to help you interpret the data:

  • The Main Trend: A solid line representing the average path of the relationship between the two currencies.
  • The Price Channel: Upper and lower boundaries that define the "normal" operating range for the pair correlation. If the price ratio stays within these boundaries, it is following its historical trend.
  • Extended Projections: The script also draws dashed lines (rays) that extend into the future. These act as projections, showing where the trend is headed based on current mathematical momentum and providing a visual guide for potential future price targets or breakout levels.

Summary of Use

Essentially, this tool helps traders identify whether the relationship between two currencies is behaving normally or if it is becoming distorted. By visualizing these pairs as a single moving channel, it simplifies complex multi-pair analysis into a clear, actionable geometric shape on your screen.

Price Data Components
Series array that contains close prices for each bar
Miscellaneous
Implements a curve of type %1
11 Views
0 Downloads
0 Favorites
InvChanel
//+------------------------------------------------------------------+
//|                                                    InvChanel.mq4 |
//|                                    Copyright © 2009, ProfitOrder |
//|                                      http://www.profitorder.com/ |
//+------------------------------------------------------------------+
#property  copyright "Copyright © 2009, ProfitOrder"
#property  link      "http://www.profitorder.com/"
#define major   1
#define minor   0

#property indicator_separate_window
#property  indicator_buffers 1
#property  indicator_color1  DodgerBlue
#property  indicator_width1  1

extern string Pair1 = "EURUSD";
extern string Pair2 = "GBPUSD";

extern color clRegress = Gold;
extern color clRegressExt = Silver;

double Buffer[];

string prefix = "InvChanel_";
string short_name;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int m_pos[2];
double m_value[2];
double a, b;
double maxdev;
  
void init() 
{
  SetIndexStyle(0, DRAW_LINE);
  SetIndexBuffer(0, Buffer);
  
  short_name = "InvChanel(" + Pair1 + ", " + Pair2 + ")";
  IndicatorShortName(short_name);
}

void deinit() 
{
  clear();
}

void start() 
{  
  int counted_bars = IndicatorCounted();
  if (counted_bars < 0) return;
  if (counted_bars > 0) counted_bars--;
  int limit = Bars-counted_bars;
  
  double val1, val2;
  int ind;

  for (int i=0; i<limit; i++) 
  {  
    ind = iBarShift(Pair1, 0, Time[i]);
    val1 = iClose(Pair1, 0, ind);
    
    ind = iBarShift(Pair2, 0, Time[i]);
    val2 = iClose(Pair2, 0, ind);

    if (val1 == 0 || val2 == 0) continue;

    Buffer[i] = val1/val2;
  }
  
  //Comment(val1, " * ", val2, " * ", Buffer[1]);
  
  //-----
  
  datetime tm1 = iTime(NULL, PERIOD_D1, 0);
  datetime tm2 = iTime(NULL, PERIOD_D1, 1);
  
  m_pos[0] = iBarShift(NULL, 0, tm1);
  m_pos[1] = iBarShift(NULL, 0, tm2);
  CalcRegr();

  //double Regr1 = a + 1*b;
  
  int win = WindowFind(short_name);
  string obj_name;
  
  obj_name = prefix + "main";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1], Time[m_pos[0]], m_value[0]);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]);
  }

  ObjectSet(obj_name, OBJPROP_RAY, false);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_SOLID);
  ObjectSet(obj_name, OBJPROP_COLOR, clRegress);

  
  obj_name = prefix + "upper";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1]+maxdev, Time[m_pos[0]], m_value[0]+maxdev);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]+maxdev);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]+maxdev);
  }

  ObjectSet(obj_name, OBJPROP_RAY, false);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_SOLID);
  ObjectSet(obj_name, OBJPROP_COLOR, clRegress);

  obj_name = prefix + "lower";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1]-maxdev, Time[m_pos[0]], m_value[0]-maxdev);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]-maxdev);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]-maxdev);
  }

  ObjectSet(obj_name, OBJPROP_RAY, false);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_SOLID);
  ObjectSet(obj_name, OBJPROP_COLOR, clRegress);

  //-----
  
  obj_name = prefix + "main_ext";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1], Time[m_pos[0]], m_value[0]);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]);
  }

  ObjectSet(obj_name, OBJPROP_RAY, true);
  ObjectSet(obj_name, OBJPROP_BACK, true);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_DASH);
  ObjectSet(obj_name, OBJPROP_COLOR, clRegressExt);

  
  obj_name = prefix + "upper_ext";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1]+maxdev, Time[m_pos[0]], m_value[0]+maxdev);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]+maxdev);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]+maxdev);
  }

  ObjectSet(obj_name, OBJPROP_RAY, true);
  ObjectSet(obj_name, OBJPROP_BACK, true);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_DASH);  
  ObjectSet(obj_name, OBJPROP_COLOR, clRegressExt);

  obj_name = prefix + "lower_ext";
  if (ObjectFind(obj_name) == -1) {
    ObjectCreate(obj_name, OBJ_TREND, win, Time[m_pos[1]], m_value[1]-maxdev, Time[m_pos[0]], m_value[0]-maxdev);
  }
  else {
    ObjectMove(obj_name, 0, Time[m_pos[1]], m_value[1]-maxdev);
    ObjectMove(obj_name, 1, Time[m_pos[0]], m_value[0]-maxdev);
  }

  ObjectSet(obj_name, OBJPROP_RAY, true);
  ObjectSet(obj_name, OBJPROP_BACK, true);
  ObjectSet(obj_name, OBJPROP_STYLE, STYLE_DASH);  
  ObjectSet(obj_name, OBJPROP_COLOR, clRegressExt);
}

void CalcRegr()
{
  int n = m_pos[1]-m_pos[0]+1;
  
//---- calculate price values
  double value = Buffer[m_pos[0]];
  double c;
  double sumy = value;
  double sumx = 0.0;
  double sumxy = 0.0;
  double sumx2 = 0.0;

  for(int i=1; i<n; i++)
  {
    value = Buffer[m_pos[0]+i];
    sumy += value;
    sumxy += value*i;
    sumx += i;
    sumx2 += i*i;
  }
     
  c = sumx2*n - sumx*sumx;
  if (c == 0.0) return;

  b = (sumxy*n - sumx*sumy)/c;
  a = (sumy - sumx*b)/n;
  m_value[0] = a;
  m_value[1] = a+b*n;

  //---- maximal deviation
  double deviation = 0;
  double dvalue = a;
  maxdev = 0;

  for(i=0; i<n; i++)
  {
    value = Buffer[m_pos[0]+i];
    dvalue += b;
    deviation = MathAbs(value-dvalue);
    if(maxdev <= deviation) maxdev = deviation;
  }
}

void clear()
{
  int total = ObjectsTotal();  
  for (int i=total-1; i >= 0; i--) 
  {
    string name = ObjectName(i);
    if (StringFind(name, prefix) == 0) ObjectDelete(name);
  }
}

Comments