Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,202 @@
|
||||
// Generated, do not edit. sha256:78fe0c105c60d329e375c6de82599c303dbce923361c391f4536e4a44fb6d65d
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { assetMetrics, saleResult, feeResult, combinePositions } from '../../shared/wealth-metrics.js';
|
||||
|
||||
const positie = ({ decimals = 8, net, buys = [], fee = 0, gift = 0 }) => ({
|
||||
decimals,
|
||||
net,
|
||||
buy_events: buys.length,
|
||||
buy_amount: buys.reduce((s, b) => s + b.amount, 0),
|
||||
buy_spot_raw: buys.reduce((s, b) => s + b.amount * b.price, 0),
|
||||
buy_fee_total: fee,
|
||||
gift_amount: gift,
|
||||
});
|
||||
|
||||
describe('assetMetrics: de waarde', () => {
|
||||
it('rekent de kleinste eenheid om naar hele eenheden en dan naar euro', () => {
|
||||
const m = assetMetrics(positie({ net: 10e8, buys: [{ amount: 10e8, price: 100 }] }), 110);
|
||||
assert.equal(m.units, 10);
|
||||
assert.equal(m.value, 1100);
|
||||
});
|
||||
|
||||
it('geeft géén waarde zonder koers, en geen nul', () => {
|
||||
const m = assetMetrics(positie({ net: 3e8, buys: [{ amount: 3e8, price: 25 }] }), null);
|
||||
assert.equal(m.value, null);
|
||||
assert.equal(m.unrealized, null);
|
||||
assert.equal(m.invested, 75, 'de inleg komt uit de boekingen en heeft geen koers van nu nodig');
|
||||
assert.equal(m.avgPrice, 25);
|
||||
});
|
||||
|
||||
it('laat de divisors tegen elkaar wegvallen in de gemiddelde aankoopkoers', () => {
|
||||
const m = assetMetrics(positie({
|
||||
net: 2e8, buys: [{ amount: 1e8, price: 100 }, { amount: 1e8, price: 120 }],
|
||||
}), 110);
|
||||
assert.equal(m.avgPrice, 110);
|
||||
assert.equal(m.invested, 220);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetMetrics: ongerealiseerd tegenover ingelegd', () => {
|
||||
it('meet ongerealiseerd tegen de gemiddelde aankoopkoers en niet tegen de inleg', () => {
|
||||
const m = assetMetrics(positie({ net: 60e8, buys: [{ amount: 100e8, price: 10 }] }), 10);
|
||||
assert.equal(m.unrealized, 0);
|
||||
assert.equal(m.invested, 1000);
|
||||
assert.equal(m.value, 600);
|
||||
});
|
||||
|
||||
it('telt de kosten bij de kostprijs en niet bij de koers', () => {
|
||||
const m = assetMetrics(positie({ net: 10e8, buys: [{ amount: 10e8, price: 10 }], fee: 5 }), 10);
|
||||
assert.equal(m.invested, 105);
|
||||
assert.equal(m.avgPrice, 10);
|
||||
assert.equal(m.avgCost, 10.5);
|
||||
assert.equal(m.unrealized, -5);
|
||||
assert.equal(m.avgPremium, 5, 'de premie is per gebeurtenis');
|
||||
});
|
||||
|
||||
it('rekent de LINK-aankoop van de gebruiker zoals de afschriften', () => {
|
||||
const m = assetMetrics(positie({ net: 5e8, buys: [{ amount: 5e8, price: 19.968 }], fee: 0.15 }), 12.65);
|
||||
assert.equal(Math.round(m.unrealized * 100) / 100, -36.74);
|
||||
assert.equal(m.avgPrice, 19.968, 'de getoonde aankoopkoers blijft zonder kosten');
|
||||
});
|
||||
|
||||
it('verdeelt de kosten naar rato over wat er na een verkoop over is', () => {
|
||||
const m = assetMetrics(positie({ net: 60e8, buys: [{ amount: 100e8, price: 10 }], fee: 20 }), 10);
|
||||
assert.equal(Math.round(m.unrealized * 100) / 100, -12);
|
||||
});
|
||||
|
||||
it('geeft geen gemiddelden zonder aankopen', () => {
|
||||
const m = assetMetrics(positie({ net: 5e8 }), 20);
|
||||
assert.equal(m.avgPrice, null);
|
||||
assert.equal(m.avgPremium, null);
|
||||
assert.equal(m.unrealized, null, 'zonder aankoopkoers is er niets om tegen af te meten');
|
||||
assert.equal(m.value, 100, 'de waarde bestaat wél: die heeft alleen de stand en de koers nodig');
|
||||
});
|
||||
});
|
||||
|
||||
describe('saleResult', () => {
|
||||
it('trekt de kostprijs inclusief kosten af van de netto opbrengst', () => {
|
||||
const r = saleResult(positie({ net: 10e8, buys: [{ amount: 10e8, price: 10 }], fee: 5 }),
|
||||
{ amount: 4e8, fiatPrice: 12, fiatFee: 1 });
|
||||
assert.equal(Math.round(r * 100) / 100, 5);
|
||||
});
|
||||
|
||||
it('sluit aan op ongerealiseerd: samen is het waarde plus opbrengst min betaald', () => {
|
||||
const voor = positie({ net: 10e8, buys: [{ amount: 10e8, price: 10 }], fee: 5 });
|
||||
const r = saleResult(voor, { amount: 4e8, fiatPrice: 12, fiatFee: 1 });
|
||||
const na = assetMetrics({ ...voor, net: 6e8 }, 12);
|
||||
assert.equal(Math.round((r + na.unrealized) * 100) / 100, 72 + 47 - 105);
|
||||
});
|
||||
|
||||
it('geeft null als het verkochte geen bekende kostprijs heeft', () => {
|
||||
assert.equal(saleResult(positie({ net: 5e8 }), { amount: 5e8, fiatPrice: 20, fiatFee: 0 }), null);
|
||||
});
|
||||
|
||||
it('telt de fee in eenheden mee als verkocht, niet als opbrengst', () => {
|
||||
const voor = positie({ net: 10e8, buys: [{ amount: 10e8, price: 10 }] });
|
||||
const r = saleResult(voor, { amount: 4e8, fiatPrice: 10, fiatFee: 0, unitFee: 1e8 });
|
||||
assert.equal(r, -10);
|
||||
const na = assetMetrics({ ...voor, net: 5e8 }, 12);
|
||||
assert.equal(r + na.unrealized, 60 + 40 - 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('feeResult', () => {
|
||||
it('rekent de fee-eenheden tegen de gemiddelde kostprijs als verlies', () => {
|
||||
const r = feeResult(positie({ net: 10e8, buys: [{ amount: 10e8, price: 10 }], fee: 5 }), 1e8);
|
||||
assert.equal(r, -10.5);
|
||||
});
|
||||
|
||||
it('geeft null als de fee-eenheden geen bekende kostprijs hebben', () => {
|
||||
assert.equal(feeResult(positie({ net: 5e8 }), 1e8), null);
|
||||
});
|
||||
|
||||
it('kost niets als de fee uit een gift komt', () => {
|
||||
assert.equal(feeResult(positie({ net: 5e8, gift: 5e8 }), 1e8), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetMetrics: metaal rekent in grammen en niet in ounces', () => {
|
||||
it('houdt de eenheid van het asset aan, wat die ook is', () => {
|
||||
const m = assetMetrics(positie({
|
||||
decimals: 4, net: 300e4,
|
||||
buys: [{ amount: 200e4, price: 50 }, { amount: 100e4, price: 50 }],
|
||||
}), 63);
|
||||
assert.equal(m.units, 300);
|
||||
assert.equal(m.value, 18900);
|
||||
assert.equal(m.invested, 15000);
|
||||
assert.equal(m.unrealized, 3900);
|
||||
});
|
||||
|
||||
it('telt de premie bij de kostprijs, in grammen', () => {
|
||||
const OZT = 31.1034768;
|
||||
const m = assetMetrics(positie({
|
||||
decimals: 4, net: OZT * 1e4, buys: [{ amount: OZT * 1e4, price: 1000 / OZT }], fee: 25,
|
||||
}), 1025 / OZT);
|
||||
assert.equal(Math.round(m.unrealized * 100) / 100, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assetMetrics: een gift draagt kostprijs nul', () => {
|
||||
it('meet alleen de betaalde eenheden tegen de gemiddelde aankoopkoers', () => {
|
||||
const m = assetMetrics(positie({ net: 150e8, buys: [{ amount: 100e8, price: 10 }], gift: 50e8 }), 20);
|
||||
assert.equal(m.value, 3000);
|
||||
assert.equal(m.unrealized, 2000);
|
||||
assert.equal(m.avgPrice, 10, 'de getoonde aankoopkoers blijft van de aankopen');
|
||||
assert.equal(m.invested, 1000, 'en de inleg ook: aan een gift is niets uitgegeven');
|
||||
});
|
||||
|
||||
it('geeft de hele waarde als er alleen een gift is', () => {
|
||||
const m = assetMetrics(positie({ net: 50e8, gift: 50e8 }), 20);
|
||||
assert.equal(m.avgPrice, null, 'er is nog steeds geen aankoopkoers om te tonen');
|
||||
assert.equal(m.value, 1000);
|
||||
assert.equal(m.unrealized, 1000);
|
||||
});
|
||||
|
||||
it('houdt een positie zonder gift op een streepje als er niets gekocht is', () => {
|
||||
const m = assetMetrics(positie({ net: 5e8 }), 20);
|
||||
assert.equal(m.unrealized, null);
|
||||
});
|
||||
|
||||
it('laat een weggegeven gift tegen de ontvangen gift wegvallen', () => {
|
||||
const m = assetMetrics(positie({ net: 100e8, buys: [{ amount: 100e8, price: 10 }], gift: 0 }), 20);
|
||||
assert.equal(m.unrealized, 1000);
|
||||
});
|
||||
|
||||
it('telt bij verkoop eerst de betaalde eenheden, dan de gift tegen nul', () => {
|
||||
const r = saleResult(positie({ net: 150e8, buys: [{ amount: 100e8, price: 10 }], gift: 50e8 }),
|
||||
{ amount: 120e8, fiatPrice: 20, fiatFee: 0 });
|
||||
assert.equal(r, 1400);
|
||||
});
|
||||
|
||||
it('gaat niet onder nul als de positie kleiner is dan de gift', () => {
|
||||
const m = assetMetrics(positie({ net: 10e8, buys: [{ amount: 100e8, price: 10 }], gift: 50e8 }), 20);
|
||||
assert.equal(m.unrealized, 200, 'de hele reststand is gift, dus kostprijs nul');
|
||||
});
|
||||
});
|
||||
|
||||
describe('combinePositions', () => {
|
||||
it('weegt het gemiddelde naar wat er gekocht is, niet per account', () => {
|
||||
const groot = positie({ net: 3e8, buys: [{ amount: 3e8, price: 100 }], fee: 6 });
|
||||
const klein = positie({ net: 1e8, buys: [{ amount: 1e8, price: 200 }], fee: 2 });
|
||||
const m = assetMetrics(combinePositions([groot, klein]), 150);
|
||||
assert.equal(m.units, 4);
|
||||
assert.equal(m.avgPrice, 125, '(3 × 100 + 1 × 200) / 4, en niet (100 + 200) / 2');
|
||||
assert.equal(m.avgPremium, 4, 'de kosten per aankoop: 8 over twee aankopen');
|
||||
assert.equal(m.invested, 508);
|
||||
assert.equal(m.unrealized, 600 - 508);
|
||||
});
|
||||
|
||||
it('telt een gift mee tegen kostprijs nul, zoals bij één account', () => {
|
||||
const gekocht = positie({ net: 1e8, buys: [{ amount: 1e8, price: 100 }] });
|
||||
const gekregen = positie({ net: 1e8, gift: 1e8 });
|
||||
assert.equal(assetMetrics(combinePositions([gekocht, gekregen]), 150).unrealized, 200);
|
||||
});
|
||||
|
||||
it('geeft bij geen enkele positie een lege positie en geen fout', () => {
|
||||
const m = assetMetrics(combinePositions([]), 150);
|
||||
assert.equal(m.units, 0);
|
||||
assert.equal(m.avgPrice, null);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user