vega-frontend-monorepo/libs/candles-chart/src/lib/data-source.ts
Bartłomiej Głownia a40f494a6f
chore: remove unused __generated__ files (#1599)
* chore: remove unused __generated__ files

* chore: change default env for type generation to testnet

* chore: fix import in assets data provider
2022-10-04 12:14:58 +02:00

211 lines
5.6 KiB
TypeScript

import type { ApolloClient } from '@apollo/client';
import type { Candle, DataSource } from 'pennant';
import { Interval as PennantInterval } from 'pennant';
import { addDecimal } from '@vegaprotocol/react-helpers';
import { ChartDocument } from './__generated___/Chart';
import type { ChartQuery, ChartQueryVariables } from './__generated___/Chart';
import {
CandlesDocument,
CandlesEventsDocument,
} from './__generated___/Candles';
import type {
CandlesQuery,
CandlesQueryVariables,
CandleFieldsFragment,
CandlesEventsSubscription,
CandlesEventsSubscriptionVariables,
} from './__generated___/Candles';
import type { Subscription } from 'zen-observable-ts';
import { Interval } from '@vegaprotocol/types';
const INTERVAL_TO_PENNANT_MAP = {
[PennantInterval.I1M]: Interval.INTERVAL_I1M,
[PennantInterval.I5M]: Interval.INTERVAL_I5M,
[PennantInterval.I15M]: Interval.INTERVAL_I15M,
[PennantInterval.I1H]: Interval.INTERVAL_I1H,
[PennantInterval.I6H]: Interval.INTERVAL_I6H,
[PennantInterval.I1D]: Interval.INTERVAL_I1D,
};
const defaultConfig = {
decimalPlaces: 5,
supportedIntervals: [
PennantInterval.I1D,
PennantInterval.I6H,
PennantInterval.I1H,
PennantInterval.I15M,
PennantInterval.I5M,
PennantInterval.I1M,
],
priceMonitoringBounds: [],
};
/**
* A data access object that provides access to the Vega GraphQL API.
*/
export class VegaDataSource implements DataSource {
client: ApolloClient<object>;
marketId: string;
partyId: null | string;
_decimalPlaces = 0;
candlesSub: Subscription | null = null;
/**
* Indicates the number of decimal places that an integer must be shifted by in order to get a correct
* number denominated in the currency of the Market.
*/
get decimalPlaces(): number {
return this._decimalPlaces;
}
/**
*
* @param client - An ApolloClient instance.
* @param marketId - Market identifier.
* @param partyId - Party identifier.
*/
constructor(
client: ApolloClient<object>,
marketId: string,
partyId: null | string = null
) {
this.client = client;
this.marketId = marketId;
this.partyId = partyId;
}
/**
* Used by the charting library to initialize itself.
*/
async onReady() {
try {
const { data } = await this.client.query<ChartQuery, ChartQueryVariables>(
{
query: ChartDocument,
variables: {
marketId: this.marketId,
},
fetchPolicy: 'no-cache',
}
);
if (data && data.market && data.market.data) {
this._decimalPlaces = data.market.decimalPlaces;
return {
decimalPlaces: this._decimalPlaces,
supportedIntervals: [
PennantInterval.I1D,
PennantInterval.I6H,
PennantInterval.I1H,
PennantInterval.I15M,
PennantInterval.I5M,
PennantInterval.I1M,
],
priceMonitoringBounds:
data.market.data.priceMonitoringBounds?.map((bounds) => ({
maxValidPrice: Number(
addDecimal(bounds.maxValidPrice, this._decimalPlaces)
),
minValidPrice: Number(
addDecimal(bounds.minValidPrice, this._decimalPlaces)
),
referencePrice: Number(
addDecimal(bounds.referencePrice, this._decimalPlaces)
),
})) ?? [],
};
} else {
return defaultConfig;
}
} catch {
return defaultConfig;
}
}
/**
* Used by the charting library to get historical data.
*/
async query(interval: PennantInterval, from: string) {
try {
const { data } = await this.client.query<
CandlesQuery,
CandlesQueryVariables
>({
query: CandlesDocument,
variables: {
marketId: this.marketId,
interval: INTERVAL_TO_PENNANT_MAP[interval],
since: from,
},
fetchPolicy: 'no-cache',
});
if (data?.market?.candlesConnection?.edges) {
const decimalPlaces = data.market.decimalPlaces;
const candles = data.market.candlesConnection.edges
.map((edge) => edge?.node)
.filter((node): node is CandleFieldsFragment => !!node)
.map((node) => parseCandle(node, decimalPlaces));
return candles;
} else {
return [];
}
} catch (error) {
return [];
}
}
/**
* Used by the charting library to create a subscription to streaming data.
*/
subscribeData(
interval: PennantInterval,
onSubscriptionData: (data: Candle) => void
) {
const res = this.client.subscribe<
CandlesEventsSubscription,
CandlesEventsSubscriptionVariables
>({
query: CandlesEventsDocument,
variables: {
marketId: this.marketId,
interval: INTERVAL_TO_PENNANT_MAP[interval],
},
});
this.candlesSub = res.subscribe(({ data }) => {
if (data) {
const candle = parseCandle(data.candles, this.decimalPlaces);
onSubscriptionData(candle);
}
});
}
/**
* Used by the charting library to clean-up a subscription to streaming data.
*/
unsubscribeData() {
this.candlesSub && this.candlesSub.unsubscribe();
}
}
function parseCandle(
candle: CandleFieldsFragment,
decimalPlaces: number
): Candle {
return {
date: new Date(candle.periodStart),
high: Number(addDecimal(candle.high, decimalPlaces)),
low: Number(addDecimal(candle.low, decimalPlaces)),
open: Number(addDecimal(candle.open, decimalPlaces)),
close: Number(addDecimal(candle.close, decimalPlaces)),
volume: Number(candle.volume),
};
}