laplace-api
Version:
Client library for Laplace API for the US stock market and BIST (Istanbul stock market) fundamental financial data.
325 lines (266 loc) • 11.3 kB
text/typescript
import { Logger } from 'winston';
import { LaplaceConfiguration } from '../utilities/configuration';
import {
FinancialFundamentalsClient,
TopMoverDirection
} from '../client/financial_fundamentals';
import './client_test_suite';
import { Region } from '../client/collections';
import { AssetType, AssetClass } from '../client/stocks';
const mockDividendsResponse = [
{
"date": "2019-12-18T06:16:00Z",
"currency": "TRY",
"netAmount": 0.00007635,
"netRatio": 0.000396200399251687,
"grossAmount": 0.000509,
"grossRatio": 0.00264133599501125,
"priceThen": 19.399,
"stoppageRatio": 0.85,
"stoppageAmount": 0.00043265
}
];
const mockStockStatsResponse = [
{
"previousClose": 307,
"ytdReturn": 0.339439655172414,
"yearlyReturn": 2.6855575955102,
"marketCap": 1425000000000,
"peRatio": 60.2794409292471,
"pbRatio": 7.32754994352451,
"yearLow": 80.56935,
"yearHigh": 339.25,
"3YearReturn": 4.65564820832651,
"5YearReturn": 17.2118318670087,
"3MonthReturn": 0.682320503304819,
"monthlyReturn": -0.0792592592592593,
"weeklyReturn": 0.0375626043405676,
"symbol": "ASELS",
"latestPrice": 310.75,
"dailyChange": 0.012214983713355,
"dayHigh": 314.75,
"dayLow": 306,
"lowerPriceLimit": 276.5,
"upperPriceLimit": 337.5,
"dayOpen": 307.25,
"eps": 4.89223038095817
}
];
const mockTopMoversResponse = [
{
"symbol": "ISKPL",
"assetClass": "equity",
"assetType": "stock",
"change": 10
}
];
describe('FinancialFundamentals', () => {
let stockClient: FinancialFundamentalsClient;
beforeAll(() => {
const config = (global as any).testSuite.config as LaplaceConfiguration;
const logger: Logger = {
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
debug: jest.fn(),
} as unknown as Logger;
stockClient = new FinancialFundamentalsClient(config, logger);
});
describe("Integration Tests", () => {
test("GetStockDividend", async () => {
const resp = await stockClient.getStockDividends("TUPRS", Region.Tr);
expect(resp).not.toBeEmpty();
const firstDividend = resp[0];
expect(typeof firstDividend.date).toBe("string");
expect(() => new Date(firstDividend.date)).not.toThrow();
expect(new Date(firstDividend.date).getTime()).not.toBeNaN();
expect(typeof firstDividend.currency).toBe("string");
expect(typeof firstDividend.netAmount).toBe("number");
expect(typeof firstDividend.netRatio).toBe("number");
expect(typeof firstDividend.grossAmount).toBe("number");
expect(typeof firstDividend.grossRatio).toBe("number");
expect(typeof firstDividend.priceThen).toBe("number");
expect(typeof firstDividend.stoppageRatio).toBe("number");
expect(typeof firstDividend.stoppageAmount).toBe("number");
});
test('GetStockStats', async () => {
const resp = await stockClient.getStockStats(['TUPRS'], Region.Tr);
expect(resp).not.toBeEmpty();
expect(resp.length).toBe(1);
const currentStockStats = resp[0];
expect(currentStockStats).not.toBeEmpty();
expect(currentStockStats.symbol).toBe('TUPRS');
expect(currentStockStats.previousClose).toBeGreaterThan(0.0);
expect(currentStockStats.marketCap).toBeGreaterThan(0.0);
expect(currentStockStats.peRatio).not.toBe(0.0);
expect(currentStockStats.pbRatio).not.toBe(0.0);
expect(currentStockStats.yearLow).toBeGreaterThan(0.0);
expect(currentStockStats.yearHigh).toBeGreaterThan(0.0);
expect(typeof currentStockStats.weeklyReturn).toBe('number');
expect(typeof currentStockStats.monthlyReturn).toBe('number');
expect(typeof currentStockStats['3MonthReturn']).toBe('number');
expect(typeof currentStockStats.ytdReturn).toBe('number');
expect(typeof currentStockStats.yearlyReturn).toBe('number');
expect(typeof currentStockStats['3YearReturn']).toBe('number');
expect(typeof currentStockStats['5YearReturn']).toBe('number');
expect(currentStockStats.latestPrice).toBeGreaterThan(0.0);
expect(typeof currentStockStats.dailyChange).toBe('number');
expect(currentStockStats.dayLow).toBeGreaterThan(0.0);
expect(currentStockStats.dayHigh).toBeGreaterThan(0.0);
expect(currentStockStats.upperPriceLimit).toBeGreaterThan(0.0);
expect(currentStockStats.lowerPriceLimit).toBeGreaterThan(0.0);
expect(currentStockStats.dayOpen).toBeGreaterThan(0.0);
expect(typeof currentStockStats.eps).toBe('number');
});
describe('GetTopMovers', () => {
const region = Region.Tr;
const page = 0;
const pageSize = 20;
async function testTopMovers(direction: TopMoverDirection, shouldBePositive: boolean) {
const result = await stockClient.getTopMovers(region, pageSize, direction, page, AssetType.Stock, AssetClass.Equity);
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBeGreaterThan(0);
result.forEach(mover => {
expect(mover).toHaveProperty('symbol');
expect(mover).toHaveProperty('change');
expect(typeof mover.symbol).toBe('string');
expect(typeof mover.change).toBe('number');
});
const directionCheck = result.every(mover =>
shouldBePositive ? mover.change > 0 : mover.change < 0
);
expect(directionCheck).toBe(true);
const assetTypeCheck = result.every(mover => mover.assetType === AssetType.Stock)
expect(assetTypeCheck).toBe(true);
const assetClassCheck = result.every(mover => mover.assetClass === AssetClass.Equity)
expect(assetClassCheck).toBe(true);
expect(result.length).toBeLessThanOrEqual(pageSize);
}
test('should return gainers data', async () => {
await testTopMovers(TopMoverDirection.Gainers, true);
});
test('should return losers data', async () => {
await testTopMovers(TopMoverDirection.Losers, false);
});
});
});
describe("Mock Tests", () => {
let client: FinancialFundamentalsClient;
let cli: { request: jest.Mock };
beforeEach(() => {
cli = { request: jest.fn() };
const config = (global as any).testSuite.config as LaplaceConfiguration;
const logger: Logger = {
info: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
debug: jest.fn(),
} as unknown as Logger;
client = new FinancialFundamentalsClient(config, logger, cli as any);
});
describe("getStockDividends", () => {
test("calls correct endpoint/params and matches raw response", async () => {
cli.request.mockResolvedValueOnce({ data: mockDividendsResponse });
const resp = await client.getStockDividends("TUPRS", Region.Tr);
expect(cli.request).toHaveBeenCalledTimes(1);
const call = cli.request.mock.calls[0][0];
expect(call.method).toBe("GET");
expect(call.url).toBe("/api/v2/stock/dividends");
expect(call.params).toEqual({ symbol: "TUPRS", region: Region.Tr });
expect(resp).toHaveLength(1);
const d = resp[0];
expect(d.date).toBe("2019-12-18T06:16:00Z");
expect(d.currency).toBe("TRY");
expect(d.netAmount).toBe(0.00007635);
expect(d.netRatio).toBe(0.000396200399251687);
expect(d.grossAmount).toBe(0.000509);
expect(d.grossRatio).toBe(0.00264133599501125);
expect(d.priceThen).toBe(19.399);
expect(d.stoppageRatio).toBe(0.85);
expect(d.stoppageAmount).toBe(0.00043265);
});
test("bubbles up request error", async () => {
cli.request.mockRejectedValueOnce(new Error("Invalid symbol"));
await expect(client.getStockDividends("INVALID", Region.Tr)).rejects.toThrow(
"Invalid symbol"
);
});
});
describe("getStockStats", () => {
test("calls correct endpoint/params and matches raw response", async () => {
cli.request.mockResolvedValueOnce({ data: mockStockStatsResponse });
const resp = await client.getStockStats(["ASELS"], Region.Tr);
expect(cli.request).toHaveBeenCalledTimes(1);
const call = cli.request.mock.calls[0][0];
expect(call.method).toBe("GET");
expect(call.url).toBe("/api/v2/stock/stats");
expect(call.params).toEqual({ symbols: "ASELS", region: Region.Tr });
expect(resp).toHaveLength(1);
const s = resp[0];
expect(s.symbol).toBe("ASELS");
expect(s.previousClose).toBe(307);
expect(s.ytdReturn).toBe(0.339439655172414);
expect(s.yearlyReturn).toBe(2.6855575955102);
expect(s.marketCap).toBe(1425000000000);
expect(s.peRatio).toBe(60.2794409292471);
expect(s.pbRatio).toBe(7.32754994352451);
expect(s.yearLow).toBe(80.56935);
expect(s.yearHigh).toBe(339.25);
expect(s["3YearReturn"]).toBe(4.65564820832651);
expect(s["5YearReturn"]).toBe(17.2118318670087);
expect(s["3MonthReturn"]).toBe(0.682320503304819);
expect(s.monthlyReturn).toBe(-0.0792592592592593);
expect(s.weeklyReturn).toBe(0.0375626043405676);
expect(s.latestPrice).toBe(310.75);
expect(s.dailyChange).toBe(0.012214983713355);
expect(s.dayHigh).toBe(314.75);
expect(s.dayLow).toBe(306);
expect(s.dayOpen).toBe(307.25);
expect(s.lowerPriceLimit).toBe(276.5);
expect(s.upperPriceLimit).toBe(337.5);
expect(s.eps).toBe(4.89223038095817);
});
test("bubbles up request error", async () => {
cli.request.mockRejectedValueOnce(new Error("Invalid symbols"));
await expect(client.getStockStats([""], Region.Tr)).rejects.toThrow("Invalid symbols");
});
});
describe("getTopMovers", () => {
test("calls correct endpoint/params and matches raw response", async () => {
cli.request.mockResolvedValueOnce({ data: mockTopMoversResponse });
const resp = await client.getTopMovers(
Region.Tr,
10,
TopMoverDirection.Gainers,
0,
AssetType.Stock,
AssetClass.Equity
);
expect(cli.request).toHaveBeenCalledTimes(1);
const call = cli.request.mock.calls[0][0];
expect(call.method).toBe("GET");
expect(call.url).toBe("/api/v2/stock/top-movers");
expect(call.params).toEqual({
region: Region.Tr,
pageSize: 10,
direction: TopMoverDirection.Gainers,
page: 0,
assetType: AssetType.Stock,
assetClass: AssetClass.Equity,
});
expect(resp).toHaveLength(1);
const m = resp[0];
expect(m.symbol).toBe("ISKPL");
expect(m.change).toBe(10);
expect(m.assetType).toBe("stock");
expect(m.assetClass).toBe("equity");
});
test("bubbles up request error", async () => {
cli.request.mockRejectedValueOnce(new Error("Bad request"));
await expect(
client.getTopMovers(Region.Tr, 10, TopMoverDirection.Gainers)
).rejects.toThrow("Bad request");
});
});
});
});