Price Data Components
Miscellaneous
0
Views
0
Downloads
0
Favorites
Unity
//|------------------------------------------------------------------+
//| Unity.mq5 |
//| Copyright (c) 2018, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//| https://www.mql5.com/en/articles/5473/ |
//| https://www.mql5.com/en/code/26112 |
//|------------------------------------------------------------------+
#property copyright "2018 © Marketeer"
#property link "https://www.mql5.com/en/users/marketeer"
#property version "1.0"
#property description "Multi-asset cluster indicator taking all currencies as a sum of squares forming market unity (1.0)"
#define BUF_NUM 15
#property indicator_separate_window
#property indicator_buffers BUF_NUM
#property indicator_plots BUF_NUM
#property indicator_color1 Green
#property indicator_color2 DarkBlue
#property indicator_color3 Red
#property indicator_color4 Gray
#property indicator_color5 Peru
#property indicator_color6 Gold
#property indicator_color7 Purple
#property indicator_color8 Teal
#property indicator_color9 LightGreen
#property indicator_color10 LightBlue
#property indicator_color11 Orange
#property indicator_color12 LightGray
#property indicator_color13 Brown
#property indicator_color14 Yellow
#property indicator_color15 Magenta
input string _1 = ""; // Cluster Indicator Settings
input string Instruments = "EURUSD,GBPUSD,USDCHF,USDJPY,AUDUSD,USDCAD,NZDUSD"; // · Instruments
input int BarLimit = 500; // · BarLimit
input ENUM_DRAW_TYPE Draw = DRAW_LINE; // · Draw
input ENUM_APPLIED_PRICE PriceType = PRICE_CLOSE; // · PriceType
input bool AbsoluteValues = false; // · AbsoluteValues
input string _2 = ""; // Data Export to CSV
input string SaveToFile = ""; // · SaveToFile
input bool ShiftLastBuffer = false; // · ShiftLastBuffer
input int BarLookback = 1; // · BarLookback
int ShiftedBuffer = -1;
bool initDone = false;
#include <CSOM/IndArray.mqh>
#include <CSOM/HashMapTemplate.mqh>
IndicatorArray buffers(BUF_NUM);
IndicatorArrayGetter getter(buffers);
string Symbols[];
int Direction[];
double Contracts[];
int SymbolCount;
HashMapTemplate<string,int> workCurrencies;
int baseIndex = 0;
string BaseCurrency;
int LastBarCount;
bool initSymbols()
{
SymbolCount = StringSplit(Instruments, ',', Symbols);
if(SymbolCount >= BUF_NUM)
{
SymbolCount = BUF_NUM - 1;
ArrayResize(Symbols, SymbolCount);
}
else if(SymbolCount == 0)
{
SymbolCount = 1;
ArrayResize(Symbols, SymbolCount);
Symbols[0] = Symbol();
}
ArrayResize(Direction, SymbolCount);
ArrayInitialize(Direction, 0);
ArrayResize(Contracts, SymbolCount);
ArrayInitialize(Contracts, 1);
string base = NULL;
for(int i = 0; i < SymbolCount; i++)
{
if(!SymbolSelect(Symbols[i], true))
{
Print("Can't select ", Symbols[i]);
return false;
}
string first, second;
first = SymbolInfoString(Symbols[i], SYMBOL_CURRENCY_BASE);
second = SymbolInfoString(Symbols[i], SYMBOL_CURRENCY_PROFIT);
if(first != second)
{
workCurrencies.inc(first, 1);
workCurrencies.inc(second, 1);
}
else
{
workCurrencies.inc(Symbols[i], 1);
}
}
if(workCurrencies.getSize() >= BUF_NUM)
{
Print("Too many symbols, max ", (BUF_NUM - 1));
return false;
}
if(ShiftLastBuffer)
{
ShiftedBuffer = workCurrencies.getSize() - 1;
}
for(int i = 0; i < workCurrencies.getSize(); i++)
{
if(workCurrencies[i] > 1)
{
if(base == NULL)
{
base = workCurrencies.getKey(i);
baseIndex = i;
}
else
{
Print("Collision: multiple base symbols: ", base, "[", workCurrencies[base], "] ", workCurrencies.getKey(i), "[", workCurrencies[i], "]");
return false;
}
}
}
BaseCurrency = base;
for(int i = 0; i < SymbolCount; i++)
{
if(SymbolInfoString(Symbols[i], SYMBOL_CURRENCY_PROFIT) == base) Direction[i] = +1;
else if(SymbolInfoString(Symbols[i], SYMBOL_CURRENCY_BASE) == base) Direction[i] = -1;
else
{
Print("Ambiguous symbol direction ", Symbols[i], ", defaults used");
Direction[i] = +1;
}
Contracts[i] = SymbolInfoDouble(Symbols[i], SYMBOL_TRADE_CONTRACT_SIZE);
}
return true;
}
int OnInit()
{
ShiftedBuffer = -1;
initDone = false;
if(!initSymbols()) return INIT_PARAMETERS_INCORRECT;
string base = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
string profit = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);
int replaceIndex = -1;
for(int i = 0; i <= SymbolCount; i++)
{
string name;
if(i == 0)
{
name = BaseCurrency;
if(name != workCurrencies.getKey(i))
{
replaceIndex = i;
}
}
else
{
if(BaseCurrency == workCurrencies.getKey(i) && replaceIndex > -1)
{
name = workCurrencies.getKey(replaceIndex);
}
else
{
name = workCurrencies.getKey(i);
}
}
PlotIndexSetString(i, PLOT_LABEL, name);
int width = (name == base || name == profit) ? 2 : 1;
PlotIndexSetInteger(i, PLOT_DRAW_TYPE, Draw);
PlotIndexSetInteger(i, PLOT_LINE_WIDTH, width);
PlotIndexSetInteger(i, PLOT_SHOW_DATA, true);
}
for(int i = SymbolCount + 1; i < BUF_NUM; i++)
{
PlotIndexSetInteger(i, PLOT_SHOW_DATA, false);
}
if(!AbsoluteValues)
{
IndicatorSetInteger(INDICATOR_LEVELS, 1);
IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, 0.0);
}
IndicatorSetString(INDICATOR_SHORTNAME, "Unity [" + (string)workCurrencies.getSize() + "] " + EnumToString(PriceType));
IndicatorSetInteger(INDICATOR_DIGITS, 5);
LastBarCount = 0;
initDone = true;
EventSetTimer(1);
Print("Unity ", __FUNCTION__, " ", Bars(_Symbol, PERIOD_CURRENT));
return INIT_SUCCEEDED;
}
#define CopyXYZ(N, S, B, A) if(Copy##N(S, PERIOD_CURRENT, B, 1, A) != 1) {Print("Failed Copy", #N, " ", S, " ", B, " ", GetLastError()); return false;}
#define CopyXYZS(N, B, A) if(Copy##N(_Symbol, PERIOD_CURRENT, B, 1, A) != 1) {Print("Failed Copy", #N, " ", _Symbol, " ", B, " ", GetLastError()); return false;}
#define CopyXYZN(N, B, C, A) if(Copy##N(_Symbol, PERIOD_CURRENT, B, C, A) != C) {Print("Failed Copy", #N, " ", _Symbol, " ", B, " ", GetLastError()); return false;}
#define CopyXYZSN(N, S, B, C, A) if(Copy##N(S, PERIOD_CURRENT, B, C, A) != C) {Print("Failed Copy", #N, " ", S, " ", B, " ", GetLastError()); return false;}
#define TOSTRING(A) #A + " = " + (string)(A) + " "
bool calculate(const int bar)
{
datetime time[1];
CopyXYZN(Time, bar, 1, time);
double w[2] = {0};
double v[][2];
ArrayResize(v, SymbolCount);
for(int j = 0; j < SymbolCount; j++)
{
if(PriceType == PRICE_OPEN)
{
CopyXYZSN(Open, Symbols[j], time[0], 2, w);
}
else
if(PriceType == PRICE_CLOSE)
{
CopyXYZSN(Close, Symbols[j], time[0], 2, w);
}
if(Direction[j] == -1)
{
w[0] = 1.0 / w[0];
w[1] = 1.0 / w[1];
}
w[1] *= Contracts[j];
w[0] *= Contracts[j];
v[j][0] = w[1];
v[j][1] = w[0];
}
double sum[2] = {1.0, 1.0};
for(int j = 0; j < SymbolCount; j++)
{
sum[0] += v[j][0] * v[j][0];
sum[1] += v[j][1] * v[j][1];
}
double base2_0 = 1.0 / sum[0];
double base2_1 = 1.0 / sum[1];
double base_0 = MathSqrt(base2_0);
double base_1 = MathSqrt(base2_1);
if(AbsoluteValues)
{
buffers[0][bar] = base_0 * Contracts[0];
}
else
{
buffers[0][bar] = base_0 / base_1 - 1.0;
}
for(int j = 1; j <= SymbolCount; j++)
{
if(AbsoluteValues)
{
buffers[j][bar] = base_0 * v[j - 1][0];
}
else
{
buffers[j][bar] = base_0 * v[j - 1][0] / (base_1 * v[j - 1][1]) - 1.0;
}
}
return true;
}
void OnTimer()
{
const double price[] = {};
if(LastBarCount != Bars(_Symbol, PERIOD_CURRENT))
{
int n = OnCalculate(Bars(_Symbol, PERIOD_CURRENT), 0, 0, price);
if(n > 0)
{
EventKillTimer();
ChartSetSymbolPeriod(0, _Symbol, PERIOD_CURRENT);
ChartRedraw();
}
}
else
{
EventKillTimer();
}
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double& price[])
{
if(!initDone) return 0;
if(LastBarCount == rates_total && prev_calculated == rates_total && PriceType != PRICE_CLOSE)
{
return prev_calculated;
}
if(prev_calculated == 0)
{
for(int i = 0; i < rates_total; i++)
{
for(int j = 0; j < BUF_NUM; j++)
{
buffers[j][i] = EMPTY_VALUE;
}
}
}
int limit = MathMin(rates_total - prev_calculated + 1, BarLimit);
for(int i = 0; i < limit; i++)
{
if(!calculate(i))
{
return 0; // will retry on next tick
}
}
static bool fileSaved = SaveToFile == "";
if(!fileSaved && !AbsoluteValues)
{
SaveBuffersToFile(SaveToFile);
fileSaved = true;
}
LastBarCount = rates_total;
return LastBarCount;
}
double GetBuffer(int index, int bar)
{
return getter[index][bar];
}
bool SaveBuffersToFile(const string filename)
{
int h = FileOpen(filename, FILE_WRITE | FILE_CSV | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_ANSI, ';');
if(h == INVALID_HANDLE) return false;
string line = "datetime";
for(int k = BarLookback - 1; k >= 0; k--)
{
for(int i = 0; i < workCurrencies.getSize(); i++)
{
line += ";" + workCurrencies.getKey(i) + (string)(k + 1);
}
}
if(ShiftLastBuffer)
{
line += ";FORECAST";
}
FileWriteString(h, line + "\n");
for(int i = BarLimit - BarLookback; i >= (ShiftedBuffer > -1 ? 1 : 0); i--)
{
datetime time[1];
CopyXYZN(Time, i, 1, time);
line = (string)time[0];
for(int k = BarLookback - 1; k >= 0; k--)
{
for(int j = 0; j < workCurrencies.getSize(); j++)
{
line += ";" + (string)GetBuffer(j, i + k);
}
}
if(ShiftLastBuffer)
{
line += ";" + (string)GetBuffer(ShiftedBuffer, i - 1); // look into the future for 1 bar
}
FileWriteString(h, line + "\n");
}
FileClose(h);
Print("File saved ", filename);
return true;
}
Comments
Markdown Formatting Guide
# H1
## H2
### H3
**bold text**
*italicized text*
[title](https://www.example.com)

`code`
```
code block
```
> blockquote
- Item 1
- Item 2
1. First item
2. Second item
---