mat.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import * as Plot from '@observablehq/plot';
  2. import {cachedFetchJSON} from './cache';
  3. const tickerSelect = document.querySelector('select#ticker') as HTMLSelectElement;
  4. const charts = document.querySelector('#charts')!;
  5. (async function () {
  6. const materials: Material[] = await fetch('https://rest.fnar.net/material/allmaterials').then((r) => r.json());
  7. const selected = document.location.hash.substring(1);
  8. for (const mat of materials.sort((a, b) => a.Ticker.localeCompare(b.Ticker))) {
  9. const option = document.createElement('option');
  10. option.value = mat.Ticker;
  11. option.textContent = `${mat.Ticker} ${mat.Name}`;
  12. if (mat.Ticker === selected)
  13. option.selected = true;
  14. tickerSelect.appendChild(option);
  15. }
  16. if (selected)
  17. render();
  18. })();
  19. tickerSelect.addEventListener('change', render);
  20. async function render() {
  21. charts.innerHTML = '';
  22. renderPriceChart(tickerSelect.value, 'IC1');
  23. }
  24. async function renderPriceChart(ticker: string, cx: string) {
  25. const cxpc: PriceChartPoint[] = await cachedFetchJSON(`https://rest.fnar.net/exchange/cxpc/${ticker}.${cx}`);
  26. const filtered = cxpc.filter((p) => p.Interval === 'HOUR_TWELVE').map((p) => ({
  27. ...p,
  28. Date: new Date(p.DateEpochMs)
  29. }));
  30. const plot = Plot.plot({
  31. inset: 6,
  32. width: 928,
  33. grid: true,
  34. y: {label: ticker},
  35. color: {domain: [-1, 0, 1], range: ['#e41a1c', '#000000', '#4daf4a']},
  36. marks: [
  37. Plot.lineY(filtered, {
  38. x: 'Date',
  39. y: (p) => p.Volume / p.Traded,
  40. }),
  41. Plot.ruleX(filtered, {
  42. x: 'Date',
  43. y1: 'Low',
  44. y2: 'High'
  45. }),
  46. /*
  47. Plot.ruleX(filtered, {
  48. x: 'Date',
  49. y: 'Traded',
  50. // stroke: (d) => Math.sign(d.Close - d.Open),
  51. // strokeWidth: 4,
  52. // strokeLinecap: 'round'
  53. })
  54. */
  55. Plot.crosshairX(filtered, {
  56. x: 'Date',
  57. y: (p) => p.Traded / p.Volume,
  58. tip: true,
  59. })
  60. ]
  61. })
  62. charts.appendChild(plot);
  63. }
  64. interface Material {
  65. Ticker: string;
  66. Name: string;
  67. }
  68. interface PriceChartPoint {
  69. Interval: 'MINUTE_FIVE' | 'MINUTE_FIFTEEN' | 'MINUTE_THIRTY' | 'HOUR_ONE' | 'HOUR_TWO' | 'HOUR_FOUR' | 'HOUR_SIX' | 'HOUR_TWELVE' | 'DAY_ONE' | 'DAY_THREE';
  70. DateEpochMs: number;
  71. High: number;
  72. Low: number;
  73. Volume: number;
  74. Traded: number;
  75. }