@exodus/market-history 10.6.1 → 10.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/lib/api/index.d.ts +20 -0
- package/lib/api/index.js +16 -0
- package/lib/atoms/index.d.ts +46 -0
- package/lib/atoms/index.js +30 -0
- package/lib/index.d.ts +159 -0
- package/lib/index.js +70 -0
- package/lib/module/constants.d.ts +2 -0
- package/lib/module/constants.js +9 -0
- package/lib/module/crop-history.d.ts +6 -0
- package/lib/module/crop-history.js +17 -0
- package/lib/module/fetch-and-process-tickers.d.ts +19 -0
- package/lib/module/fetch-and-process-tickers.js +46 -0
- package/lib/module/fetch-historical-prices.d.ts +22 -0
- package/lib/module/fetch-historical-prices.js +68 -0
- package/lib/module/find-invalid-price.d.ts +9 -0
- package/lib/module/find-invalid-price.js +16 -0
- package/lib/module/get-limit-to-fetch.d.ts +9 -0
- package/lib/module/get-limit-to-fetch.js +21 -0
- package/lib/module/index.d.ts +9 -0
- package/lib/module/index.js +576 -0
- package/lib/module/last-timestamp-from-prices-map.d.ts +3 -0
- package/lib/module/last-timestamp-from-prices-map.js +11 -0
- package/lib/module/prepare-fetch-instructions.d.ts +27 -0
- package/lib/module/prepare-fetch-instructions.js +33 -0
- package/lib/module/process-api-response.d.ts +12 -0
- package/lib/module/process-api-response.js +35 -0
- package/lib/module/try-to-load-cache.d.ts +7 -0
- package/lib/module/try-to-load-cache.js +21 -0
- package/lib/module/utils.d.ts +3 -0
- package/lib/module/utils.js +4 -0
- package/lib/plugin/index.d.ts +27 -0
- package/lib/plugin/index.js +58 -0
- package/lib/redux/id.d.ts +2 -0
- package/lib/redux/id.js +1 -0
- package/lib/redux/index.d.ts +242 -0
- package/lib/redux/index.js +18 -0
- package/lib/redux/initial-state.d.ts +3 -0
- package/lib/redux/initial-state.js +4 -0
- package/lib/redux/selectors/create-asset-daily-prices-loading.d.ts +11 -0
- package/lib/redux/selectors/create-asset-daily-prices-loading.js +14 -0
- package/lib/redux/selectors/create-asset-hourly-prices-loading.d.ts +11 -0
- package/lib/redux/selectors/create-asset-hourly-prices-loading.js +14 -0
- package/lib/redux/selectors/create-asset-minutely-prices-loading.d.ts +11 -0
- package/lib/redux/selectors/create-asset-minutely-prices-loading.js +14 -0
- package/lib/redux/selectors/daily-prices.d.ts +9 -0
- package/lib/redux/selectors/daily-prices.js +10 -0
- package/lib/redux/selectors/fiat-market-history.d.ts +12 -0
- package/lib/redux/selectors/fiat-market-history.js +11 -0
- package/lib/redux/selectors/get-asset-daily-price.d.ts +19 -0
- package/lib/redux/selectors/get-asset-daily-price.js +13 -0
- package/lib/redux/selectors/get-asset-daily-prices.d.ts +9 -0
- package/lib/redux/selectors/get-asset-daily-prices.js +9 -0
- package/lib/redux/selectors/get-asset-hourly-price.d.ts +19 -0
- package/lib/redux/selectors/get-asset-hourly-price.js +13 -0
- package/lib/redux/selectors/get-asset-hourly-prices.d.ts +9 -0
- package/lib/redux/selectors/get-asset-hourly-prices.js +9 -0
- package/lib/redux/selectors/get-asset-minutely-price.d.ts +19 -0
- package/lib/redux/selectors/get-asset-minutely-price.js +13 -0
- package/lib/redux/selectors/get-asset-minutely-prices.d.ts +9 -0
- package/lib/redux/selectors/get-asset-minutely-prices.js +9 -0
- package/lib/redux/selectors/get-daily-price.d.ts +20 -0
- package/lib/redux/selectors/get-daily-price.js +13 -0
- package/lib/redux/selectors/get-fiat-value-with-fallback.d.ts +14 -0
- package/lib/redux/selectors/get-fiat-value-with-fallback.js +17 -0
- package/lib/redux/selectors/get-hourly-price.d.ts +20 -0
- package/lib/redux/selectors/get-hourly-price.js +13 -0
- package/lib/redux/selectors/get-minutely-price.d.ts +20 -0
- package/lib/redux/selectors/get-minutely-price.js +13 -0
- package/lib/redux/selectors/get-price-with-fallback.d.ts +15 -0
- package/lib/redux/selectors/get-price-with-fallback.js +45 -0
- package/lib/redux/selectors/helpers/asset-loading-result-func.d.ts +3 -0
- package/lib/redux/selectors/helpers/asset-loading-result-func.js +5 -0
- package/lib/redux/selectors/helpers/date-utils.d.ts +6 -0
- package/lib/redux/selectors/helpers/date-utils.js +32 -0
- package/lib/redux/selectors/helpers/memoize-get-asset-price.d.ts +5 -0
- package/lib/redux/selectors/helpers/memoize-get-asset-price.js +16 -0
- package/lib/redux/selectors/helpers/memoize-get-price.d.ts +9 -0
- package/lib/redux/selectors/helpers/memoize-get-price.js +17 -0
- package/lib/redux/selectors/hourly-prices.d.ts +9 -0
- package/lib/redux/selectors/hourly-prices.js +10 -0
- package/lib/redux/selectors/index.d.ts +229 -0
- package/lib/redux/selectors/index.js +43 -0
- package/lib/redux/selectors/loading.d.ts +42 -0
- package/lib/redux/selectors/loading.js +41 -0
- package/lib/redux/selectors/minutely-prices.d.ts +9 -0
- package/lib/redux/selectors/minutely-prices.js +10 -0
- package/lib/types.d.ts +107 -0
- package/lib/types.js +1 -0
- package/lib/utils.d.ts +4 -0
- package/lib/utils.js +32 -0
- package/package.json +17 -16
- package/api/index.d.ts +0 -23
- package/api/index.js +0 -17
- package/atoms/index.js +0 -34
- package/index.d.ts +0 -8
- package/index.js +0 -90
- package/module/constants.js +0 -10
- package/module/crop-history.js +0 -20
- package/module/fetch-and-process-tickers.js +0 -66
- package/module/fetch-historical-prices.js +0 -100
- package/module/find-invalid-price.js +0 -20
- package/module/get-limit-to-fetch.js +0 -42
- package/module/index.js +0 -718
- package/module/last-timestamp-from-prices-map.js +0 -12
- package/module/prepare-fetch-instructions.js +0 -48
- package/module/process-api-response.js +0 -54
- package/module/try-to-load-cache.js +0 -41
- package/module/utils.js +0 -5
- package/plugin/index.js +0 -77
- package/redux/id.js +0 -1
- package/redux/index.js +0 -20
- package/redux/initial-state.js +0 -5
- package/redux/selectors/create-asset-daily-prices-loading.js +0 -20
- package/redux/selectors/create-asset-hourly-prices-loading.js +0 -23
- package/redux/selectors/create-asset-minutely-prices-loading.js +0 -23
- package/redux/selectors/daily-prices.js +0 -13
- package/redux/selectors/fiat-market-history.js +0 -15
- package/redux/selectors/get-asset-daily-price.js +0 -29
- package/redux/selectors/get-asset-daily-prices.js +0 -12
- package/redux/selectors/get-asset-hourly-price.js +0 -29
- package/redux/selectors/get-asset-hourly-prices.js +0 -12
- package/redux/selectors/get-asset-minutely-price.js +0 -29
- package/redux/selectors/get-asset-minutely-prices.js +0 -12
- package/redux/selectors/get-daily-price.js +0 -18
- package/redux/selectors/get-fiat-value-with-fallback.js +0 -17
- package/redux/selectors/get-hourly-price.js +0 -18
- package/redux/selectors/get-minutely-price.js +0 -18
- package/redux/selectors/get-price-with-fallback.js +0 -55
- package/redux/selectors/helpers/asset-loading-result-func.js +0 -6
- package/redux/selectors/helpers/date-utils.js +0 -59
- package/redux/selectors/helpers/memoize-get-asset-price.js +0 -16
- package/redux/selectors/helpers/memoize-get-price.js +0 -25
- package/redux/selectors/hourly-prices.js +0 -13
- package/redux/selectors/index.js +0 -48
- package/redux/selectors/loading.js +0 -66
- package/redux/selectors/minutely-prices.js +0 -13
- package/utils.js +0 -36
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.6.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/market-history@10.6.1...@exodus/market-history@10.6.2) (2026-04-07)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- fix(market-history): use Map for PriceRecord to avoid Hermes property limit crash (#15897)
|
|
11
|
+
|
|
6
12
|
## [10.6.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/market-history@10.6.0...@exodus/market-history@10.6.1) (2026-02-24)
|
|
7
13
|
|
|
8
14
|
### Performance
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MarketHistoryMonitor } from '../types.js';
|
|
2
|
+
declare const marketHistoryApiDefinition: {
|
|
3
|
+
readonly id: "marketHistoryApi";
|
|
4
|
+
readonly type: "api";
|
|
5
|
+
readonly factory: ({ marketHistoryMonitor, }: {
|
|
6
|
+
marketHistoryMonitor: MarketHistoryMonitor;
|
|
7
|
+
}) => {
|
|
8
|
+
marketHistory: {
|
|
9
|
+
update: (granularity: import("../types.js").Granularity) => Promise<void>;
|
|
10
|
+
updateAll: () => Promise<void>;
|
|
11
|
+
fetchAssetPricesFromDate: (params: {
|
|
12
|
+
assetName: string;
|
|
13
|
+
granularity: import("../types.js").Granularity;
|
|
14
|
+
startTimestamp: number;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
readonly dependencies: readonly ["marketHistoryMonitor"];
|
|
19
|
+
};
|
|
20
|
+
export default marketHistoryApiDefinition;
|
package/lib/api/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const createMarketHistoryApi = ({ marketHistoryMonitor, }) => {
|
|
2
|
+
return {
|
|
3
|
+
marketHistory: {
|
|
4
|
+
update: marketHistoryMonitor.update,
|
|
5
|
+
updateAll: marketHistoryMonitor.updateAll,
|
|
6
|
+
fetchAssetPricesFromDate: marketHistoryMonitor.fetchAssetPricesFromDate,
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
const marketHistoryApiDefinition = {
|
|
11
|
+
id: 'marketHistoryApi',
|
|
12
|
+
type: 'api',
|
|
13
|
+
factory: createMarketHistoryApi,
|
|
14
|
+
dependencies: ['marketHistoryMonitor'],
|
|
15
|
+
};
|
|
16
|
+
export default marketHistoryApiDefinition;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { RemoteConfigType } from '@exodus/remote-config';
|
|
2
|
+
import type { MarketHistoryState } from '../types.js';
|
|
3
|
+
export declare const marketHistoryAtomDefinition: {
|
|
4
|
+
readonly id: "marketHistoryAtom";
|
|
5
|
+
readonly type: "atom";
|
|
6
|
+
readonly factory: () => import("@exodus/atoms").Atom<MarketHistoryState>;
|
|
7
|
+
readonly dependencies: readonly [];
|
|
8
|
+
readonly public: true;
|
|
9
|
+
};
|
|
10
|
+
export declare const marketHistoryRefreshIntervalAtomDefinition: {
|
|
11
|
+
readonly id: "marketHistoryRefreshIntervalAtom";
|
|
12
|
+
readonly type: "atom";
|
|
13
|
+
readonly factory: ({ config, remoteConfig, }: {
|
|
14
|
+
config: {
|
|
15
|
+
path: string;
|
|
16
|
+
defaultValue: number | null;
|
|
17
|
+
};
|
|
18
|
+
remoteConfig: RemoteConfigType;
|
|
19
|
+
}) => import("@exodus/atoms").ReadonlyAtom<number | null>;
|
|
20
|
+
readonly dependencies: readonly ["config", "remoteConfig"];
|
|
21
|
+
readonly public: true;
|
|
22
|
+
};
|
|
23
|
+
export declare const marketHistoryClearCacheAtomDefinition: {
|
|
24
|
+
readonly id: "marketHistoryClearCacheAtom";
|
|
25
|
+
readonly type: "atom";
|
|
26
|
+
readonly factory: ({ config }: {
|
|
27
|
+
config: {
|
|
28
|
+
defaultValue: string | null;
|
|
29
|
+
};
|
|
30
|
+
}) => import("@exodus/atoms").Atom<string | null>;
|
|
31
|
+
readonly dependencies: readonly ["config"];
|
|
32
|
+
readonly public: true;
|
|
33
|
+
};
|
|
34
|
+
export declare const remoteConfigClearMarketHistoryCacheAtomDefinition: {
|
|
35
|
+
readonly id: "remoteConfigClearMarketHistoryCacheAtom";
|
|
36
|
+
readonly type: "atom";
|
|
37
|
+
readonly factory: ({ config, remoteConfig, }: {
|
|
38
|
+
config: {
|
|
39
|
+
path: string;
|
|
40
|
+
defaultValue: string | null;
|
|
41
|
+
};
|
|
42
|
+
remoteConfig: RemoteConfigType;
|
|
43
|
+
}) => import("@exodus/atoms").ReadonlyAtom<string | null>;
|
|
44
|
+
readonly dependencies: readonly ["config", "remoteConfig"];
|
|
45
|
+
readonly public: true;
|
|
46
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createInMemoryAtom } from '@exodus/atoms';
|
|
2
|
+
import { createRemoteConfigAtomFactory } from '@exodus/remote-config-atoms';
|
|
3
|
+
export const marketHistoryAtomDefinition = {
|
|
4
|
+
id: 'marketHistoryAtom',
|
|
5
|
+
type: 'atom',
|
|
6
|
+
factory: () => createInMemoryAtom(),
|
|
7
|
+
dependencies: [],
|
|
8
|
+
public: true,
|
|
9
|
+
};
|
|
10
|
+
export const marketHistoryRefreshIntervalAtomDefinition = {
|
|
11
|
+
id: 'marketHistoryRefreshIntervalAtom',
|
|
12
|
+
type: 'atom',
|
|
13
|
+
factory: ({ config, remoteConfig, }) => createRemoteConfigAtomFactory({ remoteConfig })(config),
|
|
14
|
+
dependencies: ['config', 'remoteConfig'],
|
|
15
|
+
public: true,
|
|
16
|
+
};
|
|
17
|
+
export const marketHistoryClearCacheAtomDefinition = {
|
|
18
|
+
id: 'marketHistoryClearCacheAtom',
|
|
19
|
+
type: 'atom',
|
|
20
|
+
factory: ({ config }) => createInMemoryAtom(config),
|
|
21
|
+
dependencies: ['config'],
|
|
22
|
+
public: true,
|
|
23
|
+
};
|
|
24
|
+
export const remoteConfigClearMarketHistoryCacheAtomDefinition = {
|
|
25
|
+
id: 'remoteConfigClearMarketHistoryCacheAtom',
|
|
26
|
+
type: 'atom',
|
|
27
|
+
factory: ({ config, remoteConfig, }) => createRemoteConfigAtomFactory({ remoteConfig })(config),
|
|
28
|
+
dependencies: ['config', 'remoteConfig'],
|
|
29
|
+
public: true,
|
|
30
|
+
};
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
type MarketHistoryConfig = {
|
|
2
|
+
clearHistoryCacheDefaultValue?: string | null;
|
|
3
|
+
remoteConfigClearHistoryCachePath?: string;
|
|
4
|
+
remoteConfigClearHistoryCacheDefaultValue?: string | null;
|
|
5
|
+
marketHistoryRefreshIntervalPath?: string;
|
|
6
|
+
marketHistoryRefreshIntervalDefaultValue?: number | null;
|
|
7
|
+
dailyRequestLimit?: number;
|
|
8
|
+
hourlyRequestLimit?: number;
|
|
9
|
+
minutelyRequestLimit?: number;
|
|
10
|
+
};
|
|
11
|
+
declare const marketHistory: ({ clearHistoryCacheDefaultValue, remoteConfigClearHistoryCachePath, remoteConfigClearHistoryCacheDefaultValue, marketHistoryRefreshIntervalPath, marketHistoryRefreshIntervalDefaultValue, dailyRequestLimit, hourlyRequestLimit, minutelyRequestLimit, }?: MarketHistoryConfig) => {
|
|
12
|
+
id: import("@exodus/safe-string").SafeString;
|
|
13
|
+
definitions: ({
|
|
14
|
+
definition: {
|
|
15
|
+
type: "monitor";
|
|
16
|
+
id: "marketHistoryMonitor";
|
|
17
|
+
factory: (args: import("./types.js").MarketHistoryMonitorDependencies) => import("./types.js").MarketHistoryMonitor;
|
|
18
|
+
dependencies: readonly ["pricingClient", "currencyAtom", "storage", "assetsModule", "clearCacheAtom", "remoteConfigClearCacheAtom", "remoteConfigRefreshIntervalAtom", "enabledAssetsAtom", "marketHistoryAtom", "logger", "getCacheKey?", "config", "synchronizedTime", "errorTracking"];
|
|
19
|
+
public: true;
|
|
20
|
+
};
|
|
21
|
+
storage: {
|
|
22
|
+
namespace: string;
|
|
23
|
+
};
|
|
24
|
+
aliases: {
|
|
25
|
+
implementationId: string;
|
|
26
|
+
interfaceId: string;
|
|
27
|
+
}[];
|
|
28
|
+
config: {
|
|
29
|
+
granularityRequestLimits: {
|
|
30
|
+
day: number;
|
|
31
|
+
hour: number;
|
|
32
|
+
minute: number;
|
|
33
|
+
};
|
|
34
|
+
defaultValue?: undefined;
|
|
35
|
+
path?: undefined;
|
|
36
|
+
};
|
|
37
|
+
} | {
|
|
38
|
+
definition: {
|
|
39
|
+
readonly id: "marketHistoryClearCacheAtom";
|
|
40
|
+
readonly type: "atom";
|
|
41
|
+
readonly factory: ({ config }: {
|
|
42
|
+
config: {
|
|
43
|
+
defaultValue: string | null;
|
|
44
|
+
};
|
|
45
|
+
}) => import("@exodus/atoms").Atom<string | null>;
|
|
46
|
+
readonly dependencies: readonly ["config"];
|
|
47
|
+
readonly public: true;
|
|
48
|
+
};
|
|
49
|
+
config: {
|
|
50
|
+
defaultValue: string | null;
|
|
51
|
+
granularityRequestLimits?: undefined;
|
|
52
|
+
path?: undefined;
|
|
53
|
+
};
|
|
54
|
+
storage?: undefined;
|
|
55
|
+
aliases?: undefined;
|
|
56
|
+
} | {
|
|
57
|
+
definition: {
|
|
58
|
+
readonly id: "remoteConfigClearMarketHistoryCacheAtom";
|
|
59
|
+
readonly type: "atom";
|
|
60
|
+
readonly factory: ({ config, remoteConfig, }: {
|
|
61
|
+
config: {
|
|
62
|
+
path: string;
|
|
63
|
+
defaultValue: string | null;
|
|
64
|
+
};
|
|
65
|
+
remoteConfig: import("features/remote-config/lib/index.js").RemoteConfigType;
|
|
66
|
+
}) => import("@exodus/atoms").ReadonlyAtom<string | null>;
|
|
67
|
+
readonly dependencies: readonly ["config", "remoteConfig"];
|
|
68
|
+
readonly public: true;
|
|
69
|
+
};
|
|
70
|
+
config: {
|
|
71
|
+
path: string;
|
|
72
|
+
defaultValue: string | null;
|
|
73
|
+
granularityRequestLimits?: undefined;
|
|
74
|
+
};
|
|
75
|
+
storage?: undefined;
|
|
76
|
+
aliases?: undefined;
|
|
77
|
+
} | {
|
|
78
|
+
definition: {
|
|
79
|
+
readonly id: "marketHistoryRefreshIntervalAtom";
|
|
80
|
+
readonly type: "atom";
|
|
81
|
+
readonly factory: ({ config, remoteConfig, }: {
|
|
82
|
+
config: {
|
|
83
|
+
path: string;
|
|
84
|
+
defaultValue: number | null;
|
|
85
|
+
};
|
|
86
|
+
remoteConfig: import("features/remote-config/lib/index.js").RemoteConfigType;
|
|
87
|
+
}) => import("@exodus/atoms").ReadonlyAtom<number | null>;
|
|
88
|
+
readonly dependencies: readonly ["config", "remoteConfig"];
|
|
89
|
+
readonly public: true;
|
|
90
|
+
};
|
|
91
|
+
config: {
|
|
92
|
+
path: string;
|
|
93
|
+
defaultValue: number | null;
|
|
94
|
+
granularityRequestLimits?: undefined;
|
|
95
|
+
};
|
|
96
|
+
storage?: undefined;
|
|
97
|
+
aliases?: undefined;
|
|
98
|
+
} | {
|
|
99
|
+
definition: {
|
|
100
|
+
readonly id: "marketHistoryLifecyclePlugin";
|
|
101
|
+
readonly type: "plugin";
|
|
102
|
+
readonly factory: ({ marketHistoryMonitor, marketHistoryAtom, appProcessAtom, port, errorTracking, }: {
|
|
103
|
+
marketHistoryMonitor: {
|
|
104
|
+
start: () => Promise<void>;
|
|
105
|
+
stop: () => void;
|
|
106
|
+
};
|
|
107
|
+
marketHistoryAtom: import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState>;
|
|
108
|
+
appProcessAtom?: import("@exodus/atoms").ReadonlyAtom<{
|
|
109
|
+
mode: string;
|
|
110
|
+
}>;
|
|
111
|
+
port: import("./types.js").MarketHistoryPort;
|
|
112
|
+
errorTracking: import("./types.js").ErrorTracking;
|
|
113
|
+
}) => {
|
|
114
|
+
onUnlock: () => void;
|
|
115
|
+
onLoad: () => void;
|
|
116
|
+
onStop: () => void;
|
|
117
|
+
};
|
|
118
|
+
readonly dependencies: readonly ["marketHistoryMonitor", "marketHistoryAtom", "appProcessAtom?", "port", "errorTracking"];
|
|
119
|
+
readonly public: true;
|
|
120
|
+
};
|
|
121
|
+
storage?: undefined;
|
|
122
|
+
aliases?: undefined;
|
|
123
|
+
config?: undefined;
|
|
124
|
+
} | {
|
|
125
|
+
definition: {
|
|
126
|
+
readonly id: "marketHistoryAtom";
|
|
127
|
+
readonly type: "atom";
|
|
128
|
+
readonly factory: () => import("@exodus/atoms").Atom<import("./types.js").MarketHistoryState>;
|
|
129
|
+
readonly dependencies: readonly [];
|
|
130
|
+
readonly public: true;
|
|
131
|
+
};
|
|
132
|
+
storage?: undefined;
|
|
133
|
+
aliases?: undefined;
|
|
134
|
+
config?: undefined;
|
|
135
|
+
} | {
|
|
136
|
+
definition: {
|
|
137
|
+
readonly id: "marketHistoryApi";
|
|
138
|
+
readonly type: "api";
|
|
139
|
+
readonly factory: ({ marketHistoryMonitor, }: {
|
|
140
|
+
marketHistoryMonitor: import("./types.js").MarketHistoryMonitor;
|
|
141
|
+
}) => {
|
|
142
|
+
marketHistory: {
|
|
143
|
+
update: (granularity: import("./types.js").Granularity) => Promise<void>;
|
|
144
|
+
updateAll: () => Promise<void>;
|
|
145
|
+
fetchAssetPricesFromDate: (params: {
|
|
146
|
+
assetName: string;
|
|
147
|
+
granularity: import("./types.js").Granularity;
|
|
148
|
+
startTimestamp: number;
|
|
149
|
+
}) => Promise<void>;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
readonly dependencies: readonly ["marketHistoryMonitor"];
|
|
153
|
+
};
|
|
154
|
+
storage?: undefined;
|
|
155
|
+
aliases?: undefined;
|
|
156
|
+
config?: undefined;
|
|
157
|
+
})[];
|
|
158
|
+
};
|
|
159
|
+
export default marketHistory;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { safeString } from '@exodus/safe-string';
|
|
2
|
+
import { marketHistoryAtomDefinition, marketHistoryClearCacheAtomDefinition, marketHistoryRefreshIntervalAtomDefinition, remoteConfigClearMarketHistoryCacheAtomDefinition, } from './atoms/index.js';
|
|
3
|
+
import marketHistoryMonitorDefinition from './module/index.js';
|
|
4
|
+
import marketHistoryPluginDefinition from './plugin/index.js';
|
|
5
|
+
import marketHistoryApiDefinition from './api/index.js';
|
|
6
|
+
const CLEAR_MARKET_HISTORY_VERSION = 'infrastructure.marketHistory.clearVersion';
|
|
7
|
+
const REFRESH_INTERVAL_ATOM_PATH = 'infrastructure.marketHistory.refreshInterval';
|
|
8
|
+
const DEFAULT_DAILY_REQUEST_LIMIT = 366;
|
|
9
|
+
const DEFAULT_HOURLY_REQUEST_LIMIT = 7 * 24;
|
|
10
|
+
const DEFAULT_MINUTELY_REQUEST_LIMIT = 2 * 60;
|
|
11
|
+
const marketHistory = ({ clearHistoryCacheDefaultValue = null, remoteConfigClearHistoryCachePath = CLEAR_MARKET_HISTORY_VERSION, remoteConfigClearHistoryCacheDefaultValue = null, marketHistoryRefreshIntervalPath = REFRESH_INTERVAL_ATOM_PATH, marketHistoryRefreshIntervalDefaultValue = null, dailyRequestLimit = DEFAULT_DAILY_REQUEST_LIMIT, hourlyRequestLimit = DEFAULT_HOURLY_REQUEST_LIMIT, minutelyRequestLimit = DEFAULT_MINUTELY_REQUEST_LIMIT, } = Object.create(null)) => {
|
|
12
|
+
return {
|
|
13
|
+
id: safeString `marketHistory`,
|
|
14
|
+
definitions: [
|
|
15
|
+
{
|
|
16
|
+
definition: { ...marketHistoryMonitorDefinition, type: 'monitor' },
|
|
17
|
+
storage: { namespace: 'marketHistory' },
|
|
18
|
+
aliases: [
|
|
19
|
+
{
|
|
20
|
+
implementationId: 'unsafeStorage',
|
|
21
|
+
interfaceId: 'storage',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
implementationId: 'marketHistoryClearCacheAtom',
|
|
25
|
+
interfaceId: 'clearCacheAtom',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
implementationId: 'remoteConfigClearMarketHistoryCacheAtom',
|
|
29
|
+
interfaceId: 'remoteConfigClearCacheAtom',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
implementationId: 'marketHistoryRefreshIntervalAtom',
|
|
33
|
+
interfaceId: 'remoteConfigRefreshIntervalAtom',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
config: {
|
|
37
|
+
granularityRequestLimits: {
|
|
38
|
+
day: dailyRequestLimit,
|
|
39
|
+
hour: hourlyRequestLimit,
|
|
40
|
+
minute: minutelyRequestLimit,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
definition: marketHistoryClearCacheAtomDefinition,
|
|
46
|
+
config: {
|
|
47
|
+
defaultValue: clearHistoryCacheDefaultValue,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
definition: remoteConfigClearMarketHistoryCacheAtomDefinition,
|
|
52
|
+
config: {
|
|
53
|
+
path: remoteConfigClearHistoryCachePath,
|
|
54
|
+
defaultValue: remoteConfigClearHistoryCacheDefaultValue,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
definition: marketHistoryRefreshIntervalAtomDefinition,
|
|
59
|
+
config: {
|
|
60
|
+
path: marketHistoryRefreshIntervalPath,
|
|
61
|
+
defaultValue: marketHistoryRefreshIntervalDefaultValue,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{ definition: marketHistoryPluginDefinition },
|
|
65
|
+
{ definition: marketHistoryAtomDefinition },
|
|
66
|
+
{ definition: marketHistoryApiDefinition },
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export default marketHistory;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ms from 'ms';
|
|
2
|
+
import lastTimestampFromPricesMap from './last-timestamp-from-prices-map.js';
|
|
3
|
+
const hourMs = ms('1h');
|
|
4
|
+
const cropHistory = ({ history, hourlyLimit, }) => {
|
|
5
|
+
const lastCachedTime = lastTimestampFromPricesMap(history);
|
|
6
|
+
if (!lastCachedTime)
|
|
7
|
+
return history;
|
|
8
|
+
const limitedTime = lastCachedTime - hourMs * hourlyLimit;
|
|
9
|
+
const result = new Map();
|
|
10
|
+
for (const [key, value] of history.entries()) {
|
|
11
|
+
if (key > limitedTime) {
|
|
12
|
+
result.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
export default cropHistory;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FetchApiFunction, Granularity, PriceData } from '../types.js';
|
|
2
|
+
type TickerToFetch = {
|
|
3
|
+
tickerSymbol: string;
|
|
4
|
+
limit: number;
|
|
5
|
+
lastCachedItem?: PriceData;
|
|
6
|
+
};
|
|
7
|
+
export default function fetchAndProcessTickers({ assetTickersToFetch, api, fiatTicker, granularity, timestamp, ignoreInvalidSymbols, historicalPricesMap, fetchedPricesMap, specificTimestamp, requestLimit, }: {
|
|
8
|
+
assetTickersToFetch: TickerToFetch[];
|
|
9
|
+
api: FetchApiFunction;
|
|
10
|
+
fiatTicker: string;
|
|
11
|
+
granularity: Granularity;
|
|
12
|
+
timestamp?: number;
|
|
13
|
+
ignoreInvalidSymbols: boolean;
|
|
14
|
+
historicalPricesMap: Map<string, Map<number, PriceData>>;
|
|
15
|
+
fetchedPricesMap: Map<string, Map<number, PriceData>>;
|
|
16
|
+
specificTimestamp?: number | null;
|
|
17
|
+
requestLimit?: number;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import processApiResponse from './process-api-response.js';
|
|
2
|
+
export default async function fetchAndProcessTickers({ assetTickersToFetch, api, fiatTicker, granularity, timestamp, ignoreInvalidSymbols, historicalPricesMap, fetchedPricesMap, specificTimestamp, requestLimit, }) {
|
|
3
|
+
if (assetTickersToFetch.length === 0) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const lastCachedItemByTicker = new Map();
|
|
7
|
+
for (const { tickerSymbol, lastCachedItem } of assetTickersToFetch) {
|
|
8
|
+
lastCachedItemByTicker.set(tickerSymbol, lastCachedItem);
|
|
9
|
+
}
|
|
10
|
+
const maxLimit = Math.max(...assetTickersToFetch.map(({ limit }) => limit));
|
|
11
|
+
const requests = [
|
|
12
|
+
assetTickersToFetch.filter(({ limit }) => limit !== maxLimit),
|
|
13
|
+
assetTickersToFetch.filter(({ limit }) => limit === maxLimit),
|
|
14
|
+
];
|
|
15
|
+
await Promise.all(requests
|
|
16
|
+
.filter((tickers) => tickers.length > 0)
|
|
17
|
+
.map(async (currentTickersToFetch) => {
|
|
18
|
+
const limit = Math.max(...currentTickersToFetch.map(({ limit }) => limit));
|
|
19
|
+
const requestParams = {
|
|
20
|
+
assets: currentTickersToFetch.map((item) => item.tickerSymbol),
|
|
21
|
+
fiatArray: [fiatTicker],
|
|
22
|
+
granularity,
|
|
23
|
+
limit,
|
|
24
|
+
timestamp,
|
|
25
|
+
ignoreInvalidSymbols,
|
|
26
|
+
};
|
|
27
|
+
const fetchedPrices = await api(requestParams);
|
|
28
|
+
Object.keys(fetchedPrices).forEach((assetTicker) => {
|
|
29
|
+
const newHistory = processApiResponse({
|
|
30
|
+
assetTicker,
|
|
31
|
+
fiatTicker,
|
|
32
|
+
fetchedPrices,
|
|
33
|
+
lastCachedItemByTicker,
|
|
34
|
+
ignoreInvalidSymbols,
|
|
35
|
+
historicalPricesMap,
|
|
36
|
+
granularity,
|
|
37
|
+
specificTimestamp,
|
|
38
|
+
requestLimit,
|
|
39
|
+
});
|
|
40
|
+
if (newHistory) {
|
|
41
|
+
fetchedPricesMap.set(assetTicker, newHistory);
|
|
42
|
+
historicalPricesMap.set(assetTicker, newHistory);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CacheEntry, FetchApiFunction, Granularity, PriceData } from '../types.js';
|
|
2
|
+
export default function fetchHistoricalPrices({ api, assetTickers, fiatTicker, granularity, getCacheFromStorage, requestLimit, timestamp, getCurrentTime, ignoreInvalidSymbols, ignoreCache, runtimeCache, getRuntimeCacheKey, }: {
|
|
3
|
+
api: FetchApiFunction;
|
|
4
|
+
assetTickers: string | string[];
|
|
5
|
+
fiatTicker: string;
|
|
6
|
+
granularity?: Granularity;
|
|
7
|
+
getCacheFromStorage: (ticker: string) => Promise<CacheEntry[] | string | undefined>;
|
|
8
|
+
requestLimit?: number;
|
|
9
|
+
timestamp?: number;
|
|
10
|
+
getCurrentTime?: () => number;
|
|
11
|
+
ignoreInvalidSymbols?: boolean;
|
|
12
|
+
ignoreCache?: boolean;
|
|
13
|
+
runtimeCache?: Map<string, CacheEntry[]>;
|
|
14
|
+
getRuntimeCacheKey?: (params: {
|
|
15
|
+
fiatTicker: string;
|
|
16
|
+
assetTicker: string;
|
|
17
|
+
granularity: Granularity;
|
|
18
|
+
}) => string;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
historicalPricesMap: Map<string, Map<number, PriceData>>;
|
|
21
|
+
fetchedPricesMap: Map<string, Map<number, PriceData>>;
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import dayjs from '@exodus/dayjs';
|
|
2
|
+
import { mapToArray } from '../utils.js';
|
|
3
|
+
import fetchAndProcessTickers from './fetch-and-process-tickers.js';
|
|
4
|
+
import prepareFetchInstructions from './prepare-fetch-instructions.js';
|
|
5
|
+
const runtimeCacheDefault = new Map();
|
|
6
|
+
const getRuntimeCacheKeyDefault = ({ fiatTicker, assetTicker, granularity, }) => `${assetTicker}_${fiatTicker}_${granularity}`;
|
|
7
|
+
export default async function fetchHistoricalPrices({ api, assetTickers, fiatTicker, granularity = 'day', getCacheFromStorage, requestLimit, timestamp, getCurrentTime = () => Date.now(), ignoreInvalidSymbols = false, ignoreCache = false, runtimeCache = runtimeCacheDefault, getRuntimeCacheKey = getRuntimeCacheKeyDefault, }) {
|
|
8
|
+
const specificTimestamp = timestamp ? dayjs(timestamp).utc().startOf(granularity).valueOf() : null;
|
|
9
|
+
const requestTimestamp = specificTimestamp ||
|
|
10
|
+
dayjs.utc(getCurrentTime()).subtract(1, granularity).startOf(granularity).valueOf();
|
|
11
|
+
const historicalPricesMap = new Map();
|
|
12
|
+
const fetchedPricesMap = new Map();
|
|
13
|
+
const tickerSymbols = Array.isArray(assetTickers) ? assetTickers : [assetTickers];
|
|
14
|
+
if (tickerSymbols.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
historicalPricesMap,
|
|
17
|
+
fetchedPricesMap,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const instructions = await Promise.all(tickerSymbols.map((tickerSymbol) => prepareFetchInstructions({
|
|
21
|
+
tickerSymbol,
|
|
22
|
+
fiatTicker,
|
|
23
|
+
granularity,
|
|
24
|
+
getCacheFromStorage,
|
|
25
|
+
requestLimit,
|
|
26
|
+
specificTimestamp,
|
|
27
|
+
ignoreCache,
|
|
28
|
+
runtimeCache,
|
|
29
|
+
getRuntimeCacheKey,
|
|
30
|
+
requestTimestamp,
|
|
31
|
+
})));
|
|
32
|
+
const assetTickersToFetch = [];
|
|
33
|
+
instructions.forEach(({ history, limit, lastCachedItem, tickerSymbol }) => {
|
|
34
|
+
historicalPricesMap.set(tickerSymbol, history);
|
|
35
|
+
if (limit) {
|
|
36
|
+
assetTickersToFetch.push({ tickerSymbol, limit, lastCachedItem });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
await fetchAndProcessTickers({
|
|
40
|
+
assetTickersToFetch,
|
|
41
|
+
api,
|
|
42
|
+
fiatTicker,
|
|
43
|
+
granularity,
|
|
44
|
+
timestamp,
|
|
45
|
+
ignoreInvalidSymbols,
|
|
46
|
+
historicalPricesMap,
|
|
47
|
+
fetchedPricesMap,
|
|
48
|
+
specificTimestamp,
|
|
49
|
+
requestLimit,
|
|
50
|
+
});
|
|
51
|
+
for (const tickerSymbol of tickerSymbols) {
|
|
52
|
+
const runtimeCacheKey = getRuntimeCacheKey({
|
|
53
|
+
fiatTicker,
|
|
54
|
+
assetTicker: tickerSymbol,
|
|
55
|
+
granularity,
|
|
56
|
+
});
|
|
57
|
+
const history = historicalPricesMap.get(tickerSymbol);
|
|
58
|
+
if (history &&
|
|
59
|
+
history.size > 0 &&
|
|
60
|
+
(fetchedPricesMap.has(tickerSymbol) || !runtimeCache.has(runtimeCacheKey))) {
|
|
61
|
+
runtimeCache.set(runtimeCacheKey, mapToArray(history));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
historicalPricesMap,
|
|
66
|
+
fetchedPricesMap,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const isValid = (value) => value !== 0 && Number.isFinite(value);
|
|
2
|
+
const findInvalidPrice = (data, lastCachedItem) => data.find((item, index) => {
|
|
3
|
+
if (!Number.isFinite(item.close) || !Number.isFinite(item.open))
|
|
4
|
+
return true;
|
|
5
|
+
if (lastCachedItem && isValid(lastCachedItem.close) && index === 0) {
|
|
6
|
+
return !isValid(item.close);
|
|
7
|
+
}
|
|
8
|
+
if (index > 0) {
|
|
9
|
+
const prevItem = data[index - 1];
|
|
10
|
+
if (!isValid(item.close) && isValid(prevItem.close))
|
|
11
|
+
return true;
|
|
12
|
+
if (!isValid(item.open) && isValid(prevItem.open))
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
export default findInvalidPrice;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Granularity, PriceData } from '../types.js';
|
|
2
|
+
declare const getLimit: ({ granularity, history, requestLimit, requestTimestamp, specificTimestamp, }: {
|
|
3
|
+
granularity: Granularity;
|
|
4
|
+
history: Map<number, PriceData>;
|
|
5
|
+
requestTimestamp: number;
|
|
6
|
+
requestLimit?: number;
|
|
7
|
+
specificTimestamp?: number | null;
|
|
8
|
+
}) => number;
|
|
9
|
+
export default getLimit;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { LIMIT, START_TIME } from './constants.js';
|
|
2
|
+
import lastTimestampFromPricesMap from './last-timestamp-from-prices-map.js';
|
|
3
|
+
import { timeToDays, timeToHours, timeToMinutes } from './utils.js';
|
|
4
|
+
const getLimit = ({ granularity, history, requestLimit, requestTimestamp, specificTimestamp, }) => {
|
|
5
|
+
if (specificTimestamp)
|
|
6
|
+
return 1;
|
|
7
|
+
const lastCachedTime = lastTimestampFromPricesMap(history);
|
|
8
|
+
const limitFromOptions = requestLimit || LIMIT[granularity];
|
|
9
|
+
if (granularity === 'minute') {
|
|
10
|
+
if (!lastCachedTime)
|
|
11
|
+
return limitFromOptions;
|
|
12
|
+
return Math.ceil(Math.min(limitFromOptions, timeToMinutes(requestTimestamp - lastCachedTime)));
|
|
13
|
+
}
|
|
14
|
+
if (granularity === 'hour') {
|
|
15
|
+
if (!lastCachedTime)
|
|
16
|
+
return limitFromOptions;
|
|
17
|
+
return Math.min(limitFromOptions, timeToHours(requestTimestamp - lastCachedTime));
|
|
18
|
+
}
|
|
19
|
+
return Math.min(limitFromOptions, timeToDays(requestTimestamp - (lastCachedTime || START_TIME)));
|
|
20
|
+
};
|
|
21
|
+
export default getLimit;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MarketHistoryMonitor, MarketHistoryMonitorDependencies } from '../types.js';
|
|
2
|
+
declare const marketHistoryMonitorDefinition: {
|
|
3
|
+
readonly id: "marketHistoryMonitor";
|
|
4
|
+
readonly type: "module";
|
|
5
|
+
readonly factory: (args: MarketHistoryMonitorDependencies) => MarketHistoryMonitor;
|
|
6
|
+
readonly dependencies: readonly ["pricingClient", "currencyAtom", "storage", "assetsModule", "clearCacheAtom", "remoteConfigClearCacheAtom", "remoteConfigRefreshIntervalAtom", "enabledAssetsAtom", "marketHistoryAtom", "logger", "getCacheKey?", "config", "synchronizedTime", "errorTracking"];
|
|
7
|
+
readonly public: true;
|
|
8
|
+
};
|
|
9
|
+
export default marketHistoryMonitorDefinition;
|