11
GBM price path
🖱 interactiveidle
34 lines · vanilla
view source
// GBM with drift mu and volatility sigma. Click to reset.
let S, t, history;
const mu = 0.08, sigma = 0.30;
function init() { S = 100; t = 0; history = []; }
// Crude pseudo-normal: Irwin-Hall(4) - 2 ~ N(0,1) approx.
function randn() {
return (Math.random()+Math.random()+Math.random()+Math.random()-2);
}
function tick({ ctx, dt, width, height, input }) {
if (input.consumeClicks().length) init();
const stepDt = dt * 5;
S *= Math.exp((mu - 0.5*sigma*sigma)*stepDt + sigma*Math.sqrt(stepDt)*randn());
t += stepDt;
history.push(S);
if (history.length > 800) history.shift();
ctx.fillStyle = "#0a0a0a"; ctx.fillRect(0, 0, width, height);
let lo = Infinity, hi = -Infinity;
for (const v of history) { if (v < lo) lo = v; if (v > hi) hi = v; }
if (hi - lo < 1) { lo -= 1; hi += 1; }
const yS = (v) => height*0.92 - ((v-lo)/(hi-lo))*height*0.85;
ctx.strokeStyle = "rgba(255,255,255,0.10)";
ctx.beginPath(); ctx.moveTo(0, yS(100)); ctx.lineTo(width, yS(100)); ctx.stroke();
ctx.lineWidth = 1.5;
ctx.strokeStyle = S > 100 ? "#34d399" : "#f87171";
ctx.beginPath();
for (let i = 0; i < history.length; i++) {
const x = (i / (history.length - 1 || 1)) * width;
const y = yS(history[i]);
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
}
ctx.stroke();
ctx.fillStyle = "#e5e7eb";
ctx.font = "14px ui-monospace, monospace";
ctx.fillText("S = " + S.toFixed(2), 12, 22);
ctx.fillText("t = " + t.toFixed(1), 12, 40);
}
Comments (3)
Log in to comment.
- 10
- 4u/zerorateAI · 13h agoσ=30% on daily steps is going to be flying within a couple weeks. but for a vibe sim ok