Files
AtreidesAssetsFree/tests/price/momentum.test.mjs
T

168 lines
6.5 KiB
JavaScript
Raw Permalink Normal View History

2026-10-29 11:57:29 +01:00
// Generated, do not edit. sha256:039e04e27156f848885588b6e6606b98400d17636d393358e29be3da504be7d4
import { describe, it, beforeEach, mock } from 'node:test';
import assert from 'node:assert/strict';
const OPGESLAGEN = new Map();
let SCHRIJVEN = 0;
mock.module('../../client/data/preferences.js', {
namedExports: {
getPref: async (scope, key, d) => (OPGESLAGEN.has(`${scope}|${key}`) ? structuredClone(OPGESLAGEN.get(`${scope}|${key}`)) : d),
setPref: async (scope, key, v) => { SCHRIJVEN++; OPGESLAGEN.set(`${scope}|${key}`, structuredClone(v)); },
},
});
const { MOMENTUM, addPrice, restore, tally, loadMomentum, recordSpot, momentumOf, clearMomentum } =
await import('../../client/price/momentum.js');
const MIN = 60000;
function reeks(prijzen, start = 0) {
return prijzen.reduce((b, p, i) => addPrice(b, p, start + i * MIN), null);
}
describe('addPrice en tally', () => {
it('telt een stijging en een daling als twee bewegingen', () => {
const t = tally(reeks([100, 101, 100]), 3 * MIN);
assert.deepEqual([t.up, t.down], [1, 1]);
});
it('een ongewijzigde prijs is geen beweging', () => {
const t = tally(reeks([100, 100, 100, 101, 101]), 5 * MIN);
assert.deepEqual([t.up, t.down], [1, 0]);
});
it('houdt alleen de laatste SIZE bewegingen', () => {
const prijzen = [];
for (let i = 0; i <= MOMENTUM.SIZE; i++) prijzen.push(1000 - i);
for (let i = 1; i <= 10; i++) prijzen.push(1000 - MOMENTUM.SIZE + i);
const t = tally(reeks(prijzen), prijzen.length * MIN);
assert.equal(t.up + t.down, MOMENTUM.SIZE);
assert.deepEqual([t.up, t.down], [10, MOMENTUM.SIZE - 10]);
});
it('een sprong na een oude referentie is geen beweging', () => {
let b = addPrice(null, 100, 0);
b = addPrice(b, 200, MOMENTUM.MAX_AGE_MS + MIN);
assert.deepEqual(b.moves, [], 'de nacht ertussen telt niet');
assert.equal(b.last, 200, 'maar de nieuwe prijs is wel de referentie');
});
it('oude bewegingen vallen uit de telling', () => {
const b = reeks([100, 101, 102]);
assert.equal(tally(b, 2 * MIN).up, 2);
assert.equal(tally(b, 2 * MIN + MOMENTUM.MAX_AGE_MS + 1).up, 0);
});
it('een ongeldige prijs laat de buffer staan', () => {
const b = reeks([100, 101]);
assert.equal(addPrice(b, null, 3 * MIN), b);
assert.equal(addPrice(b, 0, 3 * MIN), b);
assert.equal(addPrice(b, NaN, 3 * MIN), b);
});
});
describe('de richting', () => {
it('zonder beweging geen richting', () => {
assert.equal(tally(reeks([100]), 0).tone, null);
assert.equal(tally(reeks([100, 100]), 0).tone, null);
});
it('één beweging is al een richting', () => {
assert.equal(tally(reeks([100, 101]), 0).tone, 'up');
assert.equal(tally(reeks([100, 99]), 0).tone, 'down');
});
it('de meerderheid wint, ook als de laatste beweging de andere kant op gaat', () => {
assert.equal(tally(reeks([100, 101, 102, 50]), 0).tone, 'up');
});
it('gelijke stand houdt wat er stond: eerst omhoog dan omlaag blijft groen', () => {
const t = tally(reeks([100, 101, 100]), 0);
assert.equal(t.up, t.down);
assert.equal(t.tone, 'up');
});
it('en andersom blijft rood', () => {
assert.equal(tally(reeks([100, 99, 100]), 0).tone, 'down');
});
it('gelijke stand na een omslag houdt de laatste richting, niet de eerste', () => {
assert.equal(tally(reeks([100, 101, 102, 101, 100, 99, 100]), 0).tone, 'down');
});
});
describe('restore: een opgeslagen buffer terug in het geheugen', () => {
it('laat verlopen bewegingen weg en houdt de rest', () => {
const nu = MOMENTUM.MAX_AGE_MS + 10 * MIN;
const b = restore({ last: 100, lastAt: nu - MIN, moves: [{ at: 0, dir: 1 }, { at: nu - 2 * MIN, dir: -1 }] }, nu);
assert.deepEqual(b.moves, [{ at: nu - 2 * MIN, dir: -1 }]);
assert.equal(b.lastAt, nu - MIN, 'de leeftijd van de referentie gaat mee');
});
it('weigert wat geen buffer is', () => {
for (const fout of [null, 'x', {}, { last: 100, lastAt: 0 }, { last: 'a', lastAt: 0, moves: [] }]) {
assert.equal(restore(fout, 0), null, JSON.stringify(fout));
}
});
it('laat een kapotte beweging weg in plaats van de hele buffer', () => {
const b = restore({ last: 100, lastAt: 0, moves: [{ at: 0, dir: 1 }, { at: 0, dir: 7 }, null] }, 0);
assert.deepEqual(b.moves, [{ at: 0, dir: 1 }]);
});
});
describe('de opslag per asset', () => {
beforeEach(() => { clearMomentum(); OPGESLAGEN.clear(); SCHRIJVEN = 0; });
it('houdt twee assets apart', async () => {
await recordSpot(1, 100, 0);
await recordSpot(1, 101, MIN);
await recordSpot(2, 100, 0);
await recordSpot(2, 99, MIN);
assert.deepEqual([momentumOf(1, MIN).up, momentumOf(1, MIN).down], [1, 0]);
assert.deepEqual([momentumOf(2, MIN).up, momentumOf(2, MIN).down], [0, 1]);
});
it('een asset zonder bewegingen heeft geen richting', () => {
assert.deepEqual(momentumOf(9), { up: 0, down: 0, tone: null });
});
it('schrijft de buffer weg, en niet bij een ongewijzigde prijs', async () => {
await recordSpot(1, 100, 0);
await recordSpot(1, 101, MIN);
assert.equal(SCHRIJVEN, 2);
await recordSpot(1, 101, 2 * MIN);
assert.equal(SCHRIJVEN, 2, 'dezelfde prijs is geen schrijfactie');
assert.equal(OPGESLAGEN.get('momentum|1').moves.length, 1);
});
it('een nieuwe sessie gaat verder met de opgeslagen buffer', async () => {
await recordSpot(1, 100, 0);
await recordSpot(1, 101, MIN);
clearMomentum();
assert.equal(momentumOf(1, MIN).up, 0, 'nog niet geladen');
await loadMomentum(1, 2 * MIN);
assert.equal(momentumOf(1, 2 * MIN).up, 1, 'geladen');
await recordSpot(1, 102, 2 * MIN);
assert.equal(momentumOf(1, 2 * MIN).up, 2, 'en een nieuwe prijs telt erbij in plaats van eroverheen');
});
it('een buffer van gisteren telt niet mee, en zijn referentie ook niet', async () => {
const gisteren = 0;
const vandaag = MOMENTUM.MAX_AGE_MS + 60 * MIN;
const prijzen = Array.from({ length: 9 }, (_, i) => 100 + i);
for (let i = 0; i < prijzen.length; i++) await recordSpot(1, prijzen[i], gisteren + i * MIN);
clearMomentum();
await loadMomentum(1, vandaag);
assert.deepEqual(momentumOf(1, vandaag), { up: 0, down: 0, tone: null });
await recordSpot(1, 50, vandaag);
assert.equal(momentumOf(1, vandaag).down, 0, 'de val sinds gisteravond is geen beweging');
});
it('een onleesbare opgeslagen waarde begint gewoon leeg', async () => {
OPGESLAGEN.set('momentum|3', 'geen buffer');
await recordSpot(3, 100, 0);
await recordSpot(3, 101, MIN);
assert.equal(momentumOf(3, MIN).up, 1);
});
});