joemccourt-stockpriceviz.web.val.run
Readme

1d color plot of stock price

Call with symbol stock ticker and duration d (1, 5, 15, 30, 60)

Example: https://joemccourt-stockpriceviz.web.val.run/?symbol=AMD&d=60

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import process from "node:process";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export async function stockPriceViz(req: Request) {
const durations = new Set([1, 5, 15, 30, 60]);
const params = new URL(req.url).searchParams;
const symbol = params.get("symbol");
const d = params.get("d");
const resData = await fetchJSON(
`https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=${symbol}&interval=${d}min&apikey=${process.env.alphaVantage}`,
);
const data = {
resData,
symbol,
d,
};
const init = () => {
console.log(data);
const { symbol, resData, d } = data;
document.body.style.background = "#eee";
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const pointsInOrder = Object.entries(resData[`Time Series (${d}min)`]).sort(
(a, b) => new Date(a[0]).getTime() - new Date(b[0]).getTime()
);
const dates = pointsInOrder.map((e) => new Date(e[0]));
const prices = pointsInOrder.map((e) => parseFloat(e[1]["4. close"]));
const startDate = dates.at(0);
const endDate = dates.at(-1);
const dur = parseInt(d, 10) * 60 * 1000;
const span = endDate.getTime() - startDate.getTime() + dur;
const min = Math.min(...prices);
const max = Math.max(...prices);
const minColor = { r: 255, g: 0, b: 0 };
const maxColor = { r: 0, g: 255, b: 0 };
const getColorByPrice = (p) => {
const a = (max - p) / (max - min);
return {
r: minColor.r * a + maxColor.r * (1 - a),
g: minColor.g * a + maxColor.g * (1 - a),
b: minColor.b * a + maxColor.b * (1 - a),
};
};
const rgbToString = (c) => `rgb(${c.r},${c.g},${c.b})`;
const w = canvas.width;
const h = canvas.height;
dates.forEach((d, i) => {
ctx.fillStyle = rgbToString(getColorByPrice(prices[i]));
const x = w * (d.getTime() - startDate.getTime()) / span;
const dx = w * dur / span;
ctx.fillRect(x, 0, dx + 1, h);
});
const infoEl = document.getElementById("info");
infoEl.innerHTML = `${symbol}: ${startDate.toString()}(${
prices[0].toFixed(2)
}) to ${endDate.toString()}(${prices.at(-1).toFixed(2)})`;
};
const script = `const data = ${
JSON.stringify(data)
}; window.stockData = data; window.addEventListener('load', ${init});`;
const html = `
<!doctype html>
<head>
<style>body { margin: 24px }</style>
<script>${script}</script>
</head>
<body>
<div class="container">
<canvas id="canvas" width="100" height="20">
</div>
<div id="info"></div>
</body>
`;
return new Response(html, {
headers: {
"Content-Type": "text/html",
},
});
}
// Forked from @stevekrouse.stockPrice
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
October 23, 2023