phase-8:server code enhancements.
This commit is contained in:
@@ -12,7 +12,7 @@ const stubClient = {} as unknown as YahooFinanceClient;
|
||||
// Cast to any to access private methods — tests exercise internal behaviour directly.
|
||||
const advisor = new PortfolioAdvisor(stubClient) as any;
|
||||
|
||||
// Minimal holding shape used by _position and _advice (only costBasis/shares matter).
|
||||
// Minimal holding shape used by position and advice (only costBasis/shares matter).
|
||||
const holding = (costBasis: number, shares: number): PortfolioHolding => ({
|
||||
ticker: 'TEST',
|
||||
source: 'Test',
|
||||
@@ -22,45 +22,45 @@ const holding = (costBasis: number, shares: number): PortfolioHolding => ({
|
||||
});
|
||||
|
||||
test('_position: computes gain/loss correctly', () => {
|
||||
const pos = advisor._position(holding(100, 10), 150);
|
||||
const pos = advisor.position(holding(100, 10), 150);
|
||||
assert.equal(pos.gainLossPct, '50.0');
|
||||
assert.equal(pos.marketValue, '1500.00');
|
||||
assert.equal(pos.totalCost, '1000.00');
|
||||
});
|
||||
|
||||
test('_position: returns null gainLoss when price unavailable', () => {
|
||||
const pos = advisor._position(holding(100, 10), null);
|
||||
const pos = advisor.position(holding(100, 10), null);
|
||||
assert.equal(pos.gainLossPct, null);
|
||||
assert.equal(pos.marketValue, null);
|
||||
});
|
||||
|
||||
test('_advice: Strong Buy → Hold & Add', () => {
|
||||
const { action } = advisor._advice(SIGNAL.STRONG_BUY, holding(100, 10), 150);
|
||||
const { action } = advisor.advice(SIGNAL.STRONG_BUY, holding(100, 10), 150);
|
||||
assert.equal(action, '🟢 Hold & Add');
|
||||
});
|
||||
|
||||
test('_advice: Avoid + loss → Sell (Cut Loss)', () => {
|
||||
const { action } = advisor._advice(SIGNAL.AVOID, holding(150, 10), 100);
|
||||
const { action } = advisor.advice(SIGNAL.AVOID, holding(150, 10), 100);
|
||||
assert.equal(action, '🔴 Sell (Cut Loss)');
|
||||
});
|
||||
|
||||
test('_advice: Avoid + profit → Sell (Take Profits)', () => {
|
||||
const { action } = advisor._advice(SIGNAL.AVOID, holding(100, 10), 150);
|
||||
const { action } = advisor.advice(SIGNAL.AVOID, holding(100, 10), 150);
|
||||
assert.equal(action, '🔴 Sell (Take Profits)');
|
||||
});
|
||||
|
||||
test('_advice: Speculation + >20% gain → Reduce Position', () => {
|
||||
const { action } = advisor._advice(SIGNAL.SPECULATION, holding(100, 10), 125);
|
||||
const { action } = advisor.advice(SIGNAL.SPECULATION, holding(100, 10), 125);
|
||||
assert.equal(action, '🟠 Reduce Position');
|
||||
});
|
||||
|
||||
test('_cryptoAdvice: no price → No price data', () => {
|
||||
const { action } = advisor._cryptoAdvice(holding(100, 1), null);
|
||||
const { action } = advisor.cryptoAdvice(holding(100, 1), null);
|
||||
assert.equal(action, '⚪ No price data');
|
||||
});
|
||||
|
||||
test('_cryptoAdvice: >100% gain → Consider taking profits', () => {
|
||||
const { action } = advisor._cryptoAdvice(holding(10000, 1), 25000);
|
||||
const { action } = advisor.cryptoAdvice(holding(10000, 1), 25000);
|
||||
assert.equal(action, '🟠 Consider taking profits');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user