Related
My question is about the Linear Regression drawing.
The example in the documentation uses a fixed length (100), and is therefore :
shifting to the right on each new bar
of constant width (here 100 bars)
I'm trying to make it start from a custom point in time (x bars from now or bar_index or datetime...), so that :
it keeps extending on each new bar
but the starting point remains on the same location (until we change it in the settings).
That means that the length (input) would be dynamic and increase on each new bar.
I am getting the following error : Pine cannot determine the referencing length of a series. Try using max_bars_back in the study or strategy function.
Is it possible to do ?
Here is the code
//#version=4
study("Linear Regression", shorttitle="LinReg", 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)
// ====================================================================
// ====================================================================
// Original parameter (the one that should increments)
// len = input(title="Count", defval=100)
// Unsuccessful attempt : "Starting from given bar_index"
barIndexOfStartingBar = 6392 - 80 // 6392 : Current bar_index, 80 : Offset to the starting bar
len = bar_index - barIndexOfStartingBar
len := nz(len[1]) + 1
// Unsuccessful attempt : "x bars from current bar"
startingPointFromCurrentBar = input(title="Count", defval=80)
len = (bar_index + startingPointFromCurrentBar) - bar_index
len := nz(len[1]) + 1
// ====================================================================
// ====================================================================
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
// Pearson's R
var label r = na
transparent = color.new(color.white, 100)
label.delete(r[1])
if showPearson and not na(pearsonR)
r := label.new(bar_index - len + 1, lowerStartPrice, tostring(pearsonR, "#.################"), color=transparent, textcolor=#0000ff, size=size.normal, style=label.style_labelup)
With these changes you should be able to go back a few thousand bars:
study("Linear Regression", shorttitle="LinReg", overlay=true, max_bars_back = 4999)
and either one of these:
// #1
offsetToStart = input(100, minval = 1, step = 100)
len = max(1, offsetToStart)
// #2
startingBar = input(10000, minval = 1, step = 100)
len = max(1, bar_index - startingBar)
What you are looking for is called anchoring. You can do this with a trick. What I usually do is the following:
p = input("D", title="Period", type=input.resolution)
offsetToStart = input(0, title="Begin Offset") // remove the minval
newbar(p) => change(time(p)) == 0?0:1
nb = newbar(p)
bars = barssince(nb) + offsetToStart
var line l1 = na
l1 := line.new(bar_index[bars], open, bar_index[bars], open + syminfo.mintick, extend=extend.both)
line.delete(l1[1])
Remember to remove the minval. Chose the period and you can now anchor beginning of your indicator. Playaround with p
I'm trying to estimate ARMA(p,q) models with julia. I have a problem with the optimization of the log-likelihood function.
I have a function named "SsfLogLikConc" that estimates my concentrated log-likelihood and i would like to see it as function of vP, that is the value of my parameters phi and theta, and then optimize this function starting from the value vP0=zeros(cp+cq,1)where cp and cp represent the p and q orders of my ARMA(p,q) model. I tried to do it in this way:
vP0=zeros(cp+cq,1)
function f(vP)
SsfLogLikConc(vP, vy, cp, cq)
end
using Optim
res=optimize(f, vP0, BFGS())
But i keep getting errors from the optimize function even if change the method. Here is the full code:
function FisherInvTransform(Vp)
vt = (exp(2*vP)-1) ./ (exp(2*vP)+1)
end
function ReparAR(vr)
cp = length(vr)
vphi = zeros(cp,1);
vphi[1] = vr[1]
for k=2:cp
vphi[1:k-1] = vphi[1:k-1] - vr[k] * vphi[k-1:-1:1]
vphi[k] = vr[k]
end
end
function ReparMA(vr)
cq = length(vr)
vtheta = zeros(cq,1)
vtheta[1] = vr[1]
for k = 2:cq
vtheta[1:k-1] = vtheta[1:k-1] + vr[k] * vtheta[k-1:-1:1]
vtheta[k] = vr[k]
end
end
function SetStateSpaceModel(vP, cp, cq)
cm = max(cp,cq)
vphi = zeros(cm, 1)
vtheta = zeros(cm, 1)
if (cp > 0)
vphi[1:cp] = ReparAR(FisherInvTransform(vP[1:cp]))
end
if (cq > 0)
vtheta[1:cq] = ReparMA(FisherInvTransform(vP[cp+1:cp+cq]));
end
#Measurement equation: % y_{t} = Z_t \alpha_{t} + G_t \epsilon_t
mZ = [1, zeros(1, cm-1)]
mGG = 1 #G_t * G_t'
#Transition equation: % \alpha_{t+1} = T_t \alpha_{t} + H_t \epsilon_t
mT = [vphi, [eye(cm-1); zeros(1, cm-1)] ]
disp(mT)
disp( vphi)
mH = vtheta+vphi
mHH = mH*mH' #H_t * H_t'
mHG = mH
#initial conditions
va = zeros(cm,1)
mP = reshape(inv(eye(cm^2)-kron(mT,mT)) * reshape(mHH, cm^2,1) , cm, cm)
end
function KalmanFilter(vy, mZ, mGG, mT, mHH, mHG, va, mP)
cm = length(va) #n. of state elements and of diffuse elements
ck = 1
cn = length(vy)
#Initialisation of matrices and scalars
dLogf = 0
dSumSquares = 0
vInnovations = NaN(1, cn) #stores the KF innovations
vVarInnovations = NaN(1, cn)
mStatePred = NaN(cm, cn) #stores the states predictions
mCovStatePred = NaN(cm, cn)
for i = 1:cn
dv = vy[i] - mZ * va; dF = mZ * mP * mZ' + mGG;
vK = (mT * mP * mZ' + mHG) / dF;
va = mT * va + vK * dv; mP = mT * mP * mT' + mHH - vK * vK' * dF ;
if (i > ck)
vInnovations[i] = dv; vVarInnovations[i] = dF;
dLogf = dLogf + log(dF); dSumSquares = dSumSquares + dv^2 /dF;
end
mStatePred[:,i] = va; mCovStatePred[:,i] = diag(mP);
end
dSigma = dSumSquares/(cn-ck);
dLogLik = -0.5 * ((cn - ck) * log(2 * pi) + dLogf + dSumSquares );
dLogLikConc = -0.5*((cn - ck)* (log(2 * pi * dSigma)+1) + dLogf );
dPev = dSigma * dF ; # Final prediction error variance
end
function SsfLogLikConc(vP, vy, cp, cq)
SetStateSpaceModel(vP, cp, cq)
dLogF = 0; dSumSquares = 0;
cn = length(vy)
for i = 1:cn
dv = vy[i] - mZ * va; dF = mZ * mP * mZ' + mGG;
vK = (mT * mP * mZ' + mHG) / dF;
va = mT * va + vK * dv; mP = mT * mP * mT' + mHH - vK * dF * vK' ;
dLogF = dLogF + log(dF);
dSumSquares = dSumSquares + dv^2 /dF;
end
dSigma2 = dSumSquares/cn;
dLogLikConc = 0.5*( cn * (log(dSigma2)+1) + dLogF ); # concentrated LF (change of sign)
end
#Pkg.add("DataFrames")
using DataFrames;
cd("$(homedir())/Desktop")
pwd()
df=readtable("df.csv")
df
o=df[2]
mean(o)
vy=zeros(1000)
for i=1:length(o)
vy[i]=o[i]-mean(o)
end
cp = 1; cq =1;
vP0 = zeros(cp+cq,1)
function f(vP)
SsfLogLikConc(vP, vy, cp, cq)
end
#Pkg.add("Optim")
using Optim
res=optimize(f, vP0, BFGS())
Thank you for reading, I hope that someone will help me!
Here is what I want to achieve.
The parameters are both circles radius, x - centers, and y - centers. The function to make line is line(x1, y1, x2, y2).
Here is what I have now using JavaScript.
var lineX1 = circleX1 + (circleRadius1 * Math.sin(Math.atan2(circleY2 - circleY1, circleX2 - circleX1)));
var lineY1 = circleY1 + (circleRadius1 * Math.cos(Math.atan2(circleY2 - circleY1, circleX2 - circleX1)));
var lineX2 = circleX2 - (circleRadius2 * Math.sin(Math.atan2(circleY1 - circleY2, circleX1 - circleX2)));
var lineY2 = circleY2 - (circleRadius2 * Math.cos(Math.atan2(circleY1 - circleY2, circleX1 - circleX2)));
line(lineX1, lineY1, lineX2, lineY2);
But it looks like this.
There is no need in trigonometric functions.
center difference vector
dx = cx2 - cx1
dy = cy2 - cy1
len = Math.Sqrt(dx*dx + dy*dy)
normalized
udx = dx / len
udy = dy / len
line ends
lx1 = cx1 + udx * r1
ly1 = cy1 + udy * r1
lx2 = cx2 - udx * r2
ly2 = cy2 - udy * r2
You are almost correct. As #welbog pointed out, you want to use Math.atan2. Also, you swapped your cos and sin for the x/y. Finally, you only need to calculate the angle once.
Here's a demonstration:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var svg = d3.select('body')
.append('svg')
.attr('width', 500)
.attr('height', 500);
draw();
function draw() {
svg.selectAll("*").remove();
var circleRadius1 = Math.random() * 100,
circleRadius2 = Math.random() * 100,
circleX1 = Math.random() * 500,
circleY1 = Math.random() * 500,
circleX2 = Math.random() * 500,
circleY2 = Math.random() * 500;
svg.append('circle')
.attr('r', circleRadius1)
.attr('cx', circleX1)
.attr('cy', circleY1)
.style('fill', 'none')
.style('stroke', 'steelblue');
svg.append('circle')
.attr('r', circleRadius2)
.attr('cx', circleX2)
.attr('cy', circleY2)
.style('fill', 'none')
.style('stroke', 'orange');
var angle = Math.atan2(circleY2 - circleY1, circleX2 - circleX1),
lineX1 = circleX1 + (circleRadius1 * Math.cos(angle)),
lineY1 = circleY1 + (circleRadius1 * Math.sin(angle)),
lineX2 = circleX2 - (circleRadius2 * Math.cos(angle)),
lineY2 = circleY2 - (circleRadius2 * Math.sin(angle));
svg.append('line')
.attr('x1', lineX1)
.attr('y1', lineY1)
.attr('x2', lineX2)
.attr('y2', lineY2)
.style('stroke','black')
setTimeout(draw, 1000);
}
</script>
</body>
</html>
On d3js.org they have this sea of hexagons that is fully interactive, but there are no d3 docs that show how one would even start to make something like this.
From inspecting the source, you can see it's made with something called hexbin and d3js itself, but there's no other source code that actually helps understand how it's made.
Can anyone shed light on how they implemented this?
Thanks to Lars Kotthoff this is how they did it assuming you have a structure called data:
data.forEach(function(d, i) {
d.i = i % 10;
d.j = i / 10 | 0;
});
Math.seedrandom(+d3.time.hour(new Date));
d3.shuffle(data);
var height = 460,
imageWidth = 132,
imageHeight = 152,
radius = 75,
depth = 4;
var currentFocus = [innerWidth / 2, height / 2],
desiredFocus,
idle = true;
var style = document.body.style,
transform = ("webkitTransform" in style ? "-webkit-"
: "MozTransform" in style ? "-moz-"
: "msTransform" in style ? "-ms-"
: "OTransform" in style ? "-o-"
: "") + "transform";
var hexbin = d3.hexbin()
.radius(radius);
if (!("ontouchstart" in document)) d3.select("#examples")
.on("mousemove", mousemoved);
var deep = d3.select("#examples-deep");
var canvas = deep.append("canvas")
.attr("height", height);
var context = canvas.node().getContext("2d");
var svg = deep.append("svg")
.attr("height", height);
var mesh = svg.append("path")
.attr("class", "example-mesh");
var anchor = svg.append("g")
.attr("class", "example-anchor")
.selectAll("a");
var graphic = deep.selectAll("svg,canvas");
var image = new Image;
image.src = "ex.jpg?3f2d00ffdba6ced9c50f02ed42f12f6156368bd2";
image.onload = resized;
d3.select(window)
.on("resize", resized)
.each(resized);
function drawImage(d) {
context.save();
context.beginPath();
context.moveTo(0, -radius);
for (var i = 1; i < 6; ++i) {
var angle = i * Math.PI / 3,
x = Math.sin(angle) * radius,
y = -Math.cos(angle) * radius;
context.lineTo(x, y);
}
context.clip();
context.drawImage(image,
imageWidth * d.i, imageHeight * d.j,
imageWidth, imageHeight,
-imageWidth / 2, -imageHeight / 2,
imageWidth, imageHeight);
context.restore();
}
function resized() {
var deepWidth = innerWidth * (depth + 1) / depth,
deepHeight = height * (depth + 1) / depth,
centers = hexbin.size([deepWidth, deepHeight]).centers();
desiredFocus = [innerWidth / 2, height / 2];
moved();
graphic
.style("left", Math.round((innerWidth - deepWidth) / 2) + "px")
.style("top", Math.round((height - deepHeight) / 2) + "px")
.attr("width", deepWidth)
.attr("height", deepHeight);
centers.forEach(function(center, i) {
center.j = Math.round(center[1] / (radius * 1.5));
center.i = Math.round((center[0] - (center.j & 1) * radius * Math.sin(Math.PI / 3)) / (radius * 2 * Math.sin(Math.PI / 3)));
context.save();
context.translate(Math.round(center[0]), Math.round(center[1]));
drawImage(center.example = data[(center.i % 10) + ((center.j + (center.i / 10 & 1) * 5) % 10) * 10]);
context.restore();
});
mesh.attr("d", hexbin.mesh);
anchor = anchor.data(centers, function(d) { return d.i + "," + d.j; });
anchor.exit().remove();
anchor.enter().append("a")
.attr("xlink:href", function(d) { return d.example.url; })
.attr("xlink:title", function(d) { return d.example.title; })
.append("path")
.attr("d", hexbin.hexagon());
anchor
.attr("transform", function(d) { return "translate(" + d + ")"; });
}
function mousemoved() {
var m = d3.mouse(this);
desiredFocus = [
Math.round((m[0] - innerWidth / 2) / depth) * depth + innerWidth / 2,
Math.round((m[1] - height / 2) / depth) * depth + height / 2
];
moved();
}
function moved() {
if (idle) d3.timer(function() {
if (idle = Math.abs(desiredFocus[0] - currentFocus[0]) < .5 && Math.abs(desiredFocus[1] - currentFocus[1]) < .5) currentFocus = desiredFocus;
else currentFocus[0] += (desiredFocus[0] - currentFocus[0]) * .14, currentFocus[1] += (desiredFocus[1] - currentFocus[1]) * .14;
deep.style(transform, "translate(" + (innerWidth / 2 - currentFocus[0]) / depth + "px," + (height / 2 - currentFocus[1]) / depth + "px)");
return idle;
});
}
The calculations are done in the following code:
var MIN = -10.0,
MAX = 10.0,
RANGE = MAX - MIN;
getColor(max, min, val) {
var MIN_L = 40,
MAX_L = 100;
var color = new Color();
var h = 0 / 240;
var s = 80 / 240;
var l = (((MAX_L - MIN_L) / (max - min)) * val) / 240;
color.setHSL(h, s, l);
return color;
}
initGraph() {
var x = MIN,
y = MIN,
z = 0.0;
initData() {
var data = [];
for (var i = MIN; i < MAX; i++) {
var row = [];
for (var j = MIN; j < MAX; j++) {
double z = 2*( x * x + y * y);
print('$z');
row.add({
x: x,
y: y,
z: z
});
y++;
}
data.add(row);
x++;
}
return data;
}
var data = initData();
var geometry = new Geometry();
var colors = [];
var RANGE = data.length,
height = data[0].length;
data.forEach((col) {
col.forEach((val) {
geometry.vertices.add(new Vector3(x.toDouble(), y.toDouble(), z.toDouble()));
colors.add(getColor(2.5, 0, z.toDouble()));
});
});
offset(x, y) {
return x * RANGE + y;
}
for (var x = 0; x < RANGE - 1; x++) {
for (var y = 0; y < height - 1; y++) {
Vector3 vec0;
Vector3 vec1;
Vector3 n_vec;
// one of two triangle polygons in one rectangle
vec0 = (geometry.vertices[offset(x, y)] - geometry.vertices[offset(x + 1, y)]);
vec1 = (geometry.vertices[offset(x, y)] - geometry.vertices[offset(x, y + 1)]);
n_vec.crossInto(vec0, vec1).normalize();
geometry.faces.add(new Face3(offset(x, y), offset(x + 1, y), offset(x, y + 1), n_vec, [colors[offset(x, y)], colors[offset(x + 1, y)], colors[offset(x, y + 1)]]));
geometry.faces.add(new Face3(offset(x, y), offset(x, y + 1), offset(x + 1, y), n_vec.negate(), [colors[offset(x, y)], colors[offset(x, y + 1)], colors[offset(x + 1, y)]]));
// the other one
vec0 = (geometry.vertices[offset(x + 1, y)] - geometry.vertices[offset(x + 1, y + 1)]);
vec1 = (geometry.vertices[offset(x, y + 1)] - geometry.vertices[offset(x + 1, y + 1)]);
n_vec.crossInto(vec0, vec1).normalize();
geometry.faces.add(new Face3(offset(x + 1, y), offset(x + 1, y + 1), offset(x, y + 1), n_vec, [colors[offset(x + 1, y)], colors[offset(x + 1, y + 1)], colors[offset(x, y + 1)]]));
geometry.faces.add(new Face3(offset(x + 1, y), offset(x, y + 1), offset(x + 1, y + 1), n_vec.negate(), [colors[offset(x + 1, y)], colors[offset(x, y + 1)], colors[offset(x + 1, y + 1)]]));
}
}
var material = new MeshLambertMaterial(vertexColors: VertexColors);
var mesh = new Mesh(geometry, material);
scene.add(mesh);
}
The error seems to be on the occurrence of this line:
n_vec.crossInto(vec0, vec1).normalize();
What is the null object here and how do I solve this? Could the variable 'z' be causing the issue? It first showed null, and caused a similar error (that '*' cannot be applied) and I declared it as double and that got solved. I also have a suspicion in the below lines:
data.forEach((col) {
col.forEach((val) {
geometry.vertices.add(new Vector3(x.toDouble(), y.toDouble(), z.toDouble()));
n_vec is never initialized with an instance of Vector3. crossInto requires to be called on an instance, Either you create an instance first:
Vector3 n_vec = new Vector3.zero();
...
n_vec.crossInto(vec0, vec1).normalize();
Or you use the cross method, but it creates a new instance of Vector3 (you might want to avoid new instances, than I would move the variables out of the loop):
n_vec = vec0.cross(vec1).normalize();