Trabalho concluído
Termos de Referência
Есть вот такой индикатор "Кривая линейной регрессии" для сайта tradingview.com:
Его исходный код:
//@version=4
study("LR Breakthrough Alert", shorttitle="LR Br. Alert", overlay=true)
upperMult = input(title="Upper Deviation", defval=2)
lowerMult = input(title="Lower Deviation", defval=-2)
useUpperDev = input(title="Use Upper Deviation", defval=true)
useLowerDev = input(title="Use Lower Deviation", defval=true)
showPearson = input(title="Show Pearson's R", defval=true)
extendLines = input(title="Extend Lines", defval=false)
len = input(title="Count", defval=100)
src = input(title="Source", defval=close)
extend = extendLines ? extend.right : extend.none
calcSlope(src, len) =>
if not barstate.islast or len <= 1
[float(na), float(na), float(na)]
else
sumX = 0.0
sumY = 0.0
sumXSqr = 0.0
sumXY = 0.0
for i = 0 to len - 1
val = src[i]
per = i + 1.0
sumX := sumX + per
sumY := sumY + val
sumXSqr := sumXSqr + per * per
sumXY := sumXY + val * per
slope = (len * sumXY - sumX * sumY) / (len * sumXSqr - sumX * sumX)
average = sumY / len
intercept = average - slope * sumX / len + slope
[slope, average, intercept]
[s, a, i] = calcSlope(src, len)
startPrice = i + s * (len - 1)
endPrice = i
var line baseLine = na
if na(baseLine) and not na(startPrice)
baseLine := line.new(bar_index - len + 1, startPrice, bar_index, endPrice, width=1, extend=extend, color=color.red)
else
line.set_xy1(baseLine, bar_index - len + 1, startPrice)
line.set_xy2(baseLine, bar_index, endPrice)
na
calcDev(src, len, slope, average, intercept) =>
upDev = 0.0
dnDev = 0.0
stdDevAcc = 0.0
dsxx = 0.0
dsyy = 0.0
dsxy = 0.0
periods = len - 1
daY = intercept + (slope * periods) / 2
val = intercept
for i = 0 to periods
price = high[i] - val
if (price > upDev)
upDev := price
price := val - low[i]
if (price > dnDev)
dnDev := price
price := src[i]
dxt = price - average
dyt = val - daY
price := price - val
stdDevAcc := stdDevAcc + price * price
dsxx := dsxx + dxt * dxt
dsyy := dsyy + dyt * dyt
dsxy := dsxy + dxt * dyt
val := val + slope
stdDev = sqrt(stdDevAcc / (periods == 0 ? 1 : periods))
pearsonR = dsxx == 0 or dsyy == 0 ? 0 : dsxy / sqrt(dsxx * dsyy)
[stdDev, pearsonR, upDev, dnDev]
[stdDev, pearsonR, upDev, dnDev] = calcDev(src, len, s, a, i)
upperStartPrice = startPrice + (useUpperDev ? upperMult * stdDev : upDev)
upperEndPrice = endPrice + (useUpperDev ? upperMult * stdDev : upDev)
var line upper = na
lowerStartPrice = startPrice + (useLowerDev ? lowerMult * stdDev : -dnDev)
lowerEndPrice = endPrice + (useLowerDev ? lowerMult * stdDev : -dnDev)
var line lower = na
if na(upper) and not na(upperStartPrice)
upper := line.new(bar_index - len + 1, upperStartPrice, bar_index, upperEndPrice, width=1, extend=extend, color=#0000ff)
else
line.set_xy1(upper, bar_index - len + 1, upperStartPrice)
line.set_xy2(upper, bar_index, upperEndPrice)
na
if na(lower) and not na(lowerStartPrice)
lower := line.new(bar_index - len + 1, lowerStartPrice, bar_index, lowerEndPrice, width=1, extend=extend, color=#0000ff)
else
line.set_xy1(lower, bar_index - len + 1, lowerStartPrice)
line.set_xy2(lower, bar_index, lowerEndPrice)
na
Нужно написать такой же для MQ4.
Вот есть текущие наработки по нему на языке MQ4, но неправильно рисует:
#property strict
//--- input parameters
input int len=100;
input bool useUpperDev=true;
input bool useLowerDev=true;
input bool showPearson=true;
input bool extendLines=false;
//--- indicator buffers
double Label1Buffer[];
int OnInit() {
//--- indicator buffers mapping
SetIndexBuffer(0,Label1Buffer);
return(INIT_SUCCEEDED);
}
void calcDev(double &src[], int len, double slope, double average, double intercept, double &result[]) {
double upDev = 0.0;
double dnDev = 0.0;
double stdDevAcc = 0.0;
double dsxx = 0.0;
double dsyy = 0.0;
double dsxy = 0.0;
int periods = len - 1;
double daY = intercept + (slope * periods) / 2;
double val = intercept;
for (int i = 0; i <= periods; i++) {
double price = iHigh(NULL, 0, i) - val;
if (price > upDev) {
upDev = price;
}
price = val - iLow(NULL, 0, i);
if (price > dnDev) {
dnDev = price;
}
price = iClose(NULL, 0, i);
double dxt = price - average;
double dyt = val - daY;
price = price - val;
stdDevAcc = stdDevAcc + price * price;
dsxx = dsxx + dxt * dxt;
dsyy = dsyy + dyt * dyt;
dsxy = dsxy + dxt * dyt;
val = val + slope;
}
double stdDev = sqrt(stdDevAcc / (periods == 0 ? 1 : periods));
double pearsonR = (dsxx == 0 || dsyy == 0 ? 0 : dsxy / sqrt(dsxx * dsyy));
result[0] = stdDev;
result[1] = pearsonR;
result[2] = upDev;
result[3] = dnDev;
}
void calcSlope(int len, double &result[]) {
double sumX = 0.0;
double sumY = 0.0;
double sumXSqr = 0.0;
double sumXY = 0.0;
//for (int i = 0; i < len-1; i++) {
for (int i = len-1; i > 0; i--) {
double val = iClose(NULL, 0, i);
double per = i + 1.0;
sumX = sumX + per;
sumY = sumY + val;
sumXSqr = sumXSqr + per * per;
sumXY = sumXY + val * per;
}
double slope = (len * sumXY - sumX * sumY) / (len * sumXSqr - sumX * sumX);
double average = sumY / (len);
double intercept = average - slope * sumX / len + slope;
result[0] = slope;
result[1] = average;
result[2] = intercept;
}
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[]) {
double calcSlopeResults[3];
double calcDevResults[4];
calcSlope(len, calcSlopeResults);
double s = calcSlopeResults[0];
double a = calcSlopeResults[1];
double i = calcSlopeResults[2];
double startPrice = i + s * (len - 1);
double endPrice = i;
//baseLine := line.new(bar_index - len + 1, startPrice, bar_index, endPrice, width=1, extend=extend, color=color.red)
ObjectDelete(0, "LR Base Line");
datetime time1 = iTime(NULL, NULL, 1);
datetime time2 = iTime(NULL, NULL, len);
// Рисуем base line (должна быть посередине канала):
if (!ObjectCreate(0, "LR Base Line", OBJ_TREND, 0, time1, startPrice, time2, endPrice)) {
Print(__FUNCTION__, ": не удалось создать линию. Код ошибки = ", GetLastError());
return(false);
}
ObjectSetInteger(0, "LR Base Line", OBJPROP_RAY_RIGHT, false);
Print("time1: " + time1 + "; time2: " + time2 + "; startPrice: " + startPrice + "; endPrice: " + endPrice);
return(rates_total);
}
Нужно доработать/исправить этот скрипт, чтобы он рисовал канал линейной регрессии как на tradingview.com.
Чтобы проверить правильность работы индикатора, нужно в tradingview.com открыть график любой валютной пары, нажать кнопку «индикаторы» и добавить индикатор «Кривая линейной регрессии».