Skip to content

Commit

Permalink
feat: Return historical prices (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
loadpixels committed Jan 27, 2021
1 parent 7641d01 commit ea64b96
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/market/MarketAPI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {AxiosInstance} from 'axios';
import {PricesAPI} from './prices';

export interface Currency {
baseExchangeRate: number;
Expand Down Expand Up @@ -185,8 +186,11 @@ export class MarketAPI {
MARKETNAVIGATION: `/marketnavigation`,
MARKETS: `/markets`,
};
prices: PricesAPI;

constructor(private readonly apiClient: AxiosInstance) {}
constructor(private readonly apiClient: AxiosInstance) {
this.prices = new PricesAPI(apiClient);
}

/**
* Returns all markets matching the search term.
Expand Down
161 changes: 161 additions & 0 deletions src/market/prices/PricesAPI.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* eslint-disable sort-keys */
import nock from 'nock';
import {APIClient} from '../../APIClient';
import {PricesAPI, Resolution} from './PricesAPI';

describe('PricesAPI', () => {
describe('getPrices', () => {
it('returns n number of price points from now', async () => {
nock(APIClient.URL_DEMO)
.get(`${PricesAPI.URL.PRICES}/CS.D.GBPUSD.TODAY.IP?max=5&pageNumber=1&pageSize=0&resolution=HOUR_4`)
.reply(
200,
JSON.stringify({
prices: [
{
snapshotTime: '2021/01/26 00:00:00',
snapshotTimeUTC: '2021-01-26T00:00:00',
openPrice: {bid: 13676.1, ask: 13677.6, lastTraded: null},
closePrice: {bid: 13663.8, ask: 13664.7, lastTraded: null},
highPrice: {bid: 13676.8, ask: 13678.1, lastTraded: null},
lowPrice: {bid: 13659.5, ask: 13661, lastTraded: null},
lastTradedVolume: 16435,
},
{
snapshotTime: '2021/01/26 04:00:00',
snapshotTimeUTC: '2021-01-26T04:00:00',
openPrice: {bid: 13663.7, ask: 13664.6, lastTraded: null},
closePrice: {bid: 13611.5, ask: 13613, lastTraded: null},
highPrice: {bid: 13666, ask: 13667.1, lastTraded: null},
lowPrice: {bid: 13609.2, ask: 13610.1, lastTraded: null},
lastTradedVolume: 22061,
},
{
snapshotTime: '2021/01/26 08:00:00',
snapshotTimeUTC: '2021-01-26T08:00:00',
openPrice: {bid: 13611.8, ask: 13612.7, lastTraded: null},
closePrice: {bid: 13674.1, ask: 13675.6, lastTraded: null},
highPrice: {bid: 13676.2, ask: 13677.1, lastTraded: null},
lowPrice: {bid: 13610.5, ask: 13611.8, lastTraded: null},
lastTradedVolume: 29631,
},
{
snapshotTime: '2021/01/26 12:00:00',
snapshotTimeUTC: '2021-01-26T12:00:00',
openPrice: {bid: 13675.2, ask: 13676.1, lastTraded: null},
closePrice: {bid: 13741.5, ask: 13742.4, lastTraded: null},
highPrice: {bid: 13744, ask: 13745, lastTraded: null},
lowPrice: {bid: 13670.5, ask: 13671.4, lastTraded: null},
lastTradedVolume: 31848,
},
{
snapshotTime: '2021/01/26 16:00:00',
snapshotTimeUTC: '2021-01-26T16:00:00',
openPrice: {bid: 13741.4, ask: 13742.3, lastTraded: null},
closePrice: {bid: 13731.4, ask: 13732.3, lastTraded: null},
highPrice: {bid: 13742.9, ask: 13743.8, lastTraded: null},
lowPrice: {bid: 13717.5, ask: 13718.4, lastTraded: null},
lastTradedVolume: 12235,
},
],
instrumentType: 'CURRENCIES',
metadata: {
allowance: {remainingAllowance: 9945, totalAllowance: 10000, allowanceExpiry: 524060},
size: 5,
pageData: {pageSize: 20, pageNumber: 1, totalPages: 1},
},
})
);

const getPrices = await global.client.rest.market.prices.getPrices('CS.D.GBPUSD.TODAY.IP', Resolution.HOUR_4, 5);
expect(getPrices.prices.length).toBe(5);
expect(getPrices.instrumentType).toBe('CURRENCIES');
});
});
describe('getPricesBetweenDates', () => {
it('returns prices between given dates', async () => {
nock(APIClient.URL_DEMO)
.get(
`${PricesAPI.URL.PRICES}/CS.D.GBPUSD.TODAY.IP?from=2021-01-15T00%3A00%3A00.000Z&pageNumber=1&pageSize=0&resolution=HOUR_4&to=2021-01-16T00%3A00%3A00.000Z`
)
// .query(true)
.reply(
200,
JSON.stringify({
prices: [
{
snapshotTime: '2021/01/15 00:00:00',
snapshotTimeUTC: '2021-01-15T00:00:00',
openPrice: {bid: 13681.9, ask: 13684, lastTraded: null},
closePrice: {bid: 13681.4, ask: 13682.9, lastTraded: null},
highPrice: {bid: 13697.4, ask: 13698.9, lastTraded: null},
lowPrice: {bid: 13674.1, ask: 13675.3, lastTraded: null},
lastTradedVolume: 22064,
},
{
snapshotTime: '2021/01/15 04:00:00',
snapshotTimeUTC: '2021-01-15T04:00:00',
openPrice: {bid: 13681.3, ask: 13682.8, lastTraded: null},
closePrice: {bid: 13662.4, ask: 13663.3, lastTraded: null},
highPrice: {bid: 13684.3, ask: 13685.3, lastTraded: null},
lowPrice: {bid: 13657, ask: 13658.4, lastTraded: null},
lastTradedVolume: 24315,
},
{
snapshotTime: '2021/01/15 08:00:00',
snapshotTimeUTC: '2021-01-15T08:00:00',
openPrice: {bid: 13662.3, ask: 13663.2, lastTraded: null},
closePrice: {bid: 13638.9, ask: 13639.8, lastTraded: null},
highPrice: {bid: 13669.7, ask: 13670.6, lastTraded: null},
lowPrice: {bid: 13636.9, ask: 13637.9, lastTraded: null},
lastTradedVolume: 32672,
},
{
snapshotTime: '2021/01/15 12:00:00',
snapshotTimeUTC: '2021-01-15T12:00:00',
openPrice: {bid: 13638.4, ask: 13639.3, lastTraded: null},
closePrice: {bid: 13583.5, ask: 13584.4, lastTraded: null},
highPrice: {bid: 13641.3, ask: 13642.2, lastTraded: null},
lowPrice: {bid: 13571.8, ask: 13572.7, lastTraded: null},
lastTradedVolume: 43169,
},
{
snapshotTime: '2021/01/15 16:00:00',
snapshotTimeUTC: '2021-01-15T16:00:00',
openPrice: {bid: 13583.6, ask: 13584.5, lastTraded: null},
closePrice: {bid: 13579.2, ask: 13580.7, lastTraded: null},
highPrice: {bid: 13606.2, ask: 13607.1, lastTraded: null},
lowPrice: {bid: 13574.2, ask: 13575.1, lastTraded: null},
lastTradedVolume: 23937,
},
{
snapshotTime: '2021/01/15 20:00:00',
snapshotTimeUTC: '2021-01-15T20:00:00',
openPrice: {bid: 13579.1, ask: 13580.6, lastTraded: null},
closePrice: {bid: 13582.1, ask: 13592.1, lastTraded: null},
highPrice: {bid: 13589.1, ask: 13596.3, lastTraded: null},
lowPrice: {bid: 13574.8, ask: 13576.3, lastTraded: null},
lastTradedVolume: 8749,
},
],
instrumentType: 'CURRENCIES',
metadata: {
allowance: {remainingAllowance: 9994, totalAllowance: 10000, allowanceExpiry: 604799},
size: 6,
pageData: {pageSize: 6, pageNumber: 1, totalPages: 1},
},
})
);

const getPricesBetweenDates = await global.client.rest.market.prices.getPricesBetweenDates(
'CS.D.GBPUSD.TODAY.IP',
Resolution.HOUR_4,
new Date('2021-01-15T00:00:00'),
new Date('2021-01-16T00:00:00')
);

expect(getPricesBetweenDates.prices.length).toBe(6);
expect(getPricesBetweenDates.instrumentType).toBe('CURRENCIES');
});
});
});
153 changes: 153 additions & 0 deletions src/market/prices/PricesAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {AxiosInstance} from 'axios';
import querystring from 'querystring';
interface BidAsk {
ask: number;
bid: number;
lastTraded: number | null;
}
export interface CandleStick {
closePrice: BidAsk;
highPrice: BidAsk;
lastTradedVolume: number;
lowPrice: BidAsk;
openPrice: BidAsk;
snapshotTime: Date | string;
snapshotTimeUTC: Date | string;
}

export interface HistoricalPricesAllowance {
allowanceExpiry: number;
remainingAllowance: number;
totalAllowance: number;
}

export interface HistoricalPricesMetadata {
allowance: HistoricalPricesAllowance;
pageData: HistoricalPricesPagination;
size: number;
}

export interface HistoricalPricesPagination {
pageNumber: number;
pageSize: number;
totalPages: number;
}

export interface HistoricalPricesResponse {
instrumentType:
| 'BUNGEE_COMMODITIES'
| 'BUNGEE_CURRENCIES'
| 'BUNGEE_INDICES'
| 'COMMODITIES'
| 'CURRENCIES'
| 'INDICES'
| 'OPT_COMMODITIES'
| 'OPT_CURRENCIES'
| 'OPT_INDICES'
| 'OPT_RATES'
| 'OPT_SHARES'
| 'RATES'
| 'SECTORS'
| 'SHARES'
| 'SPRINT_MARKET'
| 'TEST_MARKET'
| 'UNKNOWN';
metadata: HistoricalPricesMetadata;
prices: CandleStick[];
}

export enum Resolution {
DAY = 'DAY',
HOUR = 'HOUR',
HOUR_2 = 'HOUR_2',
HOUR_3 = 'HOUR_3',
HOUR_4 = 'HOUR_4',
MINUTE = 'MINUTE',
MINUTE_10 = 'MINUTE_10',
MINUTE_15 = 'MINUTE_15',
MINUTE_2 = 'MINUTE_2',
MINUTE_3 = 'MINUTE_3',
MINUTE_30 = 'MINUTE_30',
MINUTE_5 = 'MINUTE_5',
MONTH = 'MONTH',
SECOND = 'SECOND',
WEEK = 'WEEK',
}

export enum ResolutionTime {
DAY = 86400000,
HOUR = 3600000,
HOUR_2 = 7200000,
HOUR_3 = 10800000,
HOUR_4 = 14400000,
MINUTE = 60000,
MINUTE_10 = 600000,
MINUTE_15 = 900000,
MINUTE_2 = 120000,
MINUTE_3 = 180000,
MINUTE_30 = 1800000,
MINUTE_5 = 300000,
MONTH = 2419200000,
SECOND = 1000,
WEEK = 604800000,
}

export class PricesAPI {
static readonly URL = {
PRICES: '/prices',
};

constructor(private readonly apiClient: AxiosInstance) {}

/**
* Returns historical prices between given dates
* NOTE: Uses the V3 API response
* @param epic - The epic of the market to be retrieved
* @param resolution - the time resolution to get
* @param startDate - Start date
* @param endDate - End date - must be later than start date
* @param pageSize - Number of candles per page of results (default 0 - no pagination)
* @param pageNumber - the page of results to return
* @see https://labs.ig.com/rest-trading-api-reference/service-detail?id=521
*/
async getPricesBetweenDates(
epic: string,
resolution: Resolution,
startDate: Date,
endDate: Date,
pageSize: number = 0,
pageNumber: number = 1
): Promise<HistoricalPricesResponse> {
const qs = querystring.stringify({
from: startDate.toISOString(),
pageNumber,
pageSize,
resolution,
to: endDate.toISOString(),
});

const resource = `${PricesAPI.URL.PRICES}/${epic}?${qs}`;

const response = await this.apiClient.get<HistoricalPricesResponse>(resource, {headers: {Version: 3}});

return response.data;
}

async getPrices(
epic: string,
resolution: Resolution,
pointCount: number,
pageSize: number = 0,
pageNumber: number = 1
): Promise<HistoricalPricesResponse> {
const qs = querystring.stringify({
max: pointCount,
pageNumber,
pageSize,
resolution,
});
const resource = `${PricesAPI.URL.PRICES}/${epic}?${qs}`;
const response = await this.apiClient.get<HistoricalPricesResponse>(resource, {headers: {Version: 3}});
return response.data;
}
}
1 change: 1 addition & 0 deletions src/market/prices/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './PricesAPI';

0 comments on commit ea64b96

Please sign in to comment.