init
This commit is contained in:
13
packages/core/quotes/index.ts
Normal file
13
packages/core/quotes/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import {ApiResponse} from "./types";
|
||||
|
||||
export async function collect_quote(x: { symbol: string, apiKey: string }) {
|
||||
const {symbol, apiKey} = x;
|
||||
|
||||
const data: ApiResponse = await fetch(`https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=${symbol}`, {
|
||||
headers: {
|
||||
"x-cmc_pro_api_key": apiKey
|
||||
}
|
||||
}).then((symbolDataRequest) => symbolDataRequest.json());
|
||||
|
||||
return data;
|
||||
}
|
77
packages/core/quotes/models.ts
Normal file
77
packages/core/quotes/models.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {types, flow, Instance} from "mobx-state-tree";
|
||||
import {collect_quote} from './index';
|
||||
|
||||
|
||||
const QuoteData = types.optional(types.frozen(), {})
|
||||
|
||||
export const QuoteStore = types
|
||||
.model("QuoteStore", {
|
||||
apiKey: types.string,
|
||||
quotes: types.map(QuoteData),
|
||||
})
|
||||
.views(self => ({
|
||||
getQuote(symbol) {
|
||||
return self.quotes.get(symbol);
|
||||
},
|
||||
|
||||
hasQuote(symbol) {
|
||||
return self.quotes.has(symbol);
|
||||
}
|
||||
}))
|
||||
.actions(self => {
|
||||
|
||||
const extractUsefulData = (data, symbol) => {
|
||||
return data.data[symbol].map(qd => ({
|
||||
symbol: qd.symbol,
|
||||
slug: qd.slug,
|
||||
tags: qd.tags,
|
||||
id: qd.id,
|
||||
...qd.quote.USD
|
||||
})).at(0);
|
||||
};
|
||||
|
||||
const fetchQuote = flow(function* (symbol) {
|
||||
try {
|
||||
const data = yield collect_quote({symbol, apiKey: self.apiKey});
|
||||
const usefulData = extractUsefulData(data, symbol);
|
||||
|
||||
|
||||
self.quotes.set(symbol, usefulData);
|
||||
|
||||
return usefulData;
|
||||
} catch (error) {
|
||||
console.error(`An error occurred fetching the quote for symbol: ${symbol}`, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
const fetchQuotes = flow(function* (symbols) {
|
||||
const results = {};
|
||||
|
||||
for (const symbol of symbols) {
|
||||
|
||||
if (self.quotes.has(symbol)) {
|
||||
results[symbol] = self.quotes.get(symbol);
|
||||
} else {
|
||||
|
||||
const data = yield fetchQuote(symbol);
|
||||
results[symbol] = extractUsefulData(data, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
});
|
||||
|
||||
const clearCache = () => {
|
||||
self.quotes.clear();
|
||||
};
|
||||
|
||||
return {
|
||||
fetchQuote,
|
||||
fetchQuotes,
|
||||
clearCache
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
export type QuoteManagerType = Instance<typeof QuoteStore>;
|
17
packages/core/quotes/quote.test.ts
Normal file
17
packages/core/quotes/quote.test.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {describe, it} from 'vitest';
|
||||
import {QuoteStore} from "./models";
|
||||
|
||||
describe('QuoteStore', () => {
|
||||
it('should get data for symbols using the quoteManager', async () => {
|
||||
const testApiKey = '';
|
||||
const quoteManager = QuoteStore.create({
|
||||
apiKey: testApiKey,
|
||||
});
|
||||
|
||||
const symbol = 'BTC';
|
||||
|
||||
const data = await quoteManager.fetchQuote(symbol);
|
||||
|
||||
console.log(JSON.stringify(data));
|
||||
});
|
||||
});
|
71
packages/core/quotes/types.ts
Normal file
71
packages/core/quotes/types.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
type Status = {
|
||||
timestamp: string;
|
||||
error_code: number;
|
||||
error_message: string | null;
|
||||
elapsed: number;
|
||||
credit_count: number;
|
||||
notice: string | null;
|
||||
};
|
||||
|
||||
type Tag = {
|
||||
slug: string;
|
||||
name: string;
|
||||
category: string;
|
||||
};
|
||||
|
||||
type Quote = {
|
||||
USD: {
|
||||
price: number | null;
|
||||
volume_24h: number;
|
||||
volume_change_24h: number;
|
||||
percent_change_1h: number;
|
||||
percent_change_24h: number;
|
||||
percent_change_7d: number;
|
||||
percent_change_30d: number;
|
||||
percent_change_60d: number;
|
||||
percent_change_90d: number;
|
||||
market_cap: number | null;
|
||||
market_cap_dominance: number | null;
|
||||
fully_diluted_market_cap: number | null;
|
||||
tvl: number | null;
|
||||
last_updated: string;
|
||||
};
|
||||
};
|
||||
|
||||
type Platform = {
|
||||
id: number;
|
||||
name: string;
|
||||
symbol: string;
|
||||
slug: string;
|
||||
token_address: string;
|
||||
};
|
||||
|
||||
type Cryptocurrency = {
|
||||
id: number;
|
||||
name: string;
|
||||
symbol: string;
|
||||
slug: string;
|
||||
num_market_pairs: number;
|
||||
date_added: string;
|
||||
tags: Tag[];
|
||||
max_supply: number | null;
|
||||
circulating_supply: number | null;
|
||||
total_supply: number;
|
||||
platform: Platform | null;
|
||||
is_active: number;
|
||||
infinite_supply: boolean;
|
||||
cmc_rank: number | null;
|
||||
is_fiat: number;
|
||||
self_reported_circulating_supply: number | null;
|
||||
self_reported_market_cap: number | null;
|
||||
tvl_ratio: number | null;
|
||||
last_updated: string;
|
||||
quote: Quote;
|
||||
};
|
||||
|
||||
export type ApiResponse = {
|
||||
status: Status;
|
||||
data: {
|
||||
[SYMBOL: string]: Cryptocurrency[];
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user