bulltrackers-module 1.0.404 → 1.0.406
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/functions/computation-system/context/ContextFactory.js +11 -5
- package/functions/computation-system/executors/MetaExecutor.js +35 -4
- package/functions/computation-system/executors/StandardExecutor.js +22 -14
- package/functions/task-engine/helpers/popular_investor_helpers.js +51 -75
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Factory for creating the Computation Context.
|
|
3
3
|
* UPDATED: Injects verification and rankings data into context globally and locally.
|
|
4
|
+
* UPDATED: Added support for historical ranking data in both Standard and Meta contexts.
|
|
4
5
|
*/
|
|
5
6
|
const mathLayer = require('../layers/index');
|
|
6
7
|
const { LEGACY_MAPPING } = require('../topology/HashManager');
|
|
@@ -21,8 +22,10 @@ class ContextFactory {
|
|
|
21
22
|
todayPortfolio, yesterdayPortfolio, todayHistory, yesterdayHistory,
|
|
22
23
|
userId, userType, dateStr, metadata, mappings, insights, socialData,
|
|
23
24
|
computedDependencies, previousComputedDependencies, config, deps,
|
|
24
|
-
verification,
|
|
25
|
-
|
|
25
|
+
verification,
|
|
26
|
+
rankings, yesterdayRankings, // User-specific rank entries
|
|
27
|
+
allRankings, allRankingsYesterday, // Global rank lists
|
|
28
|
+
allVerifications
|
|
26
29
|
} = options;
|
|
27
30
|
|
|
28
31
|
return {
|
|
@@ -32,7 +35,8 @@ class ContextFactory {
|
|
|
32
35
|
portfolio: { today: todayPortfolio, yesterday: yesterdayPortfolio },
|
|
33
36
|
history: { today: todayHistory, yesterday: yesterdayHistory },
|
|
34
37
|
verification: verification || null,
|
|
35
|
-
rankEntry: rankings || null
|
|
38
|
+
rankEntry: rankings || null,
|
|
39
|
+
rankEntryYesterday: yesterdayRankings || null
|
|
36
40
|
},
|
|
37
41
|
date: { today: dateStr },
|
|
38
42
|
insights: { today: insights?.today, yesterday: insights?.yesterday },
|
|
@@ -42,9 +46,9 @@ class ContextFactory {
|
|
|
42
46
|
computed: computedDependencies || {},
|
|
43
47
|
previousComputed: previousComputedDependencies || {},
|
|
44
48
|
meta: metadata, config, deps,
|
|
45
|
-
// [NEW] Global Data Injection for Comparative Logic (Similarity, Ranking position, etc.)
|
|
46
49
|
globalData: {
|
|
47
50
|
rankings: allRankings || [],
|
|
51
|
+
rankingsYesterday: allRankingsYesterday || [],
|
|
48
52
|
verifications: allVerifications || {}
|
|
49
53
|
}
|
|
50
54
|
};
|
|
@@ -54,7 +58,8 @@ class ContextFactory {
|
|
|
54
58
|
const {
|
|
55
59
|
dateStr, metadata, mappings, insights, socialData, prices,
|
|
56
60
|
computedDependencies, previousComputedDependencies, config, deps,
|
|
57
|
-
allRankings,
|
|
61
|
+
allRankings, allRankingsYesterday, // [UPDATED] Accepted here
|
|
62
|
+
allVerifications
|
|
58
63
|
} = options;
|
|
59
64
|
|
|
60
65
|
return {
|
|
@@ -69,6 +74,7 @@ class ContextFactory {
|
|
|
69
74
|
meta: metadata, config, deps,
|
|
70
75
|
globalData: {
|
|
71
76
|
rankings: allRankings || [],
|
|
77
|
+
rankingsYesterday: allRankingsYesterday || [], // [UPDATED] Injected here
|
|
72
78
|
verifications: allVerifications || {}
|
|
73
79
|
}
|
|
74
80
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* UPDATED: Uses CachedDataLoader for all data access.
|
|
4
4
|
* UPDATED: Tracks processed shard/item counts.
|
|
5
5
|
* UPDATED: Sends 'isInitialWrite: true' for robust cleanup.
|
|
6
|
+
* UPDATED: Support for historical rankings in Meta Context.
|
|
6
7
|
*/
|
|
7
8
|
const { normalizeName } = require('../utils/utils');
|
|
8
9
|
const { CachedDataLoader } = require('../data/CachedDataLoader');
|
|
@@ -13,9 +14,20 @@ class MetaExecutor {
|
|
|
13
14
|
static async run(date, calcs, passName, config, deps, rootData, fetchedDeps, previousFetchedDeps) {
|
|
14
15
|
const dStr = date.toISOString().slice(0, 10);
|
|
15
16
|
const { logger, db } = deps;
|
|
16
|
-
const { CachedDataLoader } = require('../data/CachedDataLoader');
|
|
17
17
|
const loader = new CachedDataLoader(config, deps);
|
|
18
18
|
|
|
19
|
+
// [FIX] Check if any meta calculation needs history
|
|
20
|
+
const needsHistory = calcs.some(c => c.isHistorical);
|
|
21
|
+
let rankingsYesterday = null;
|
|
22
|
+
|
|
23
|
+
if (needsHistory) {
|
|
24
|
+
const prevDate = new Date(date);
|
|
25
|
+
prevDate.setUTCDate(prevDate.getUTCDate() - 1);
|
|
26
|
+
const prevStr = prevDate.toISOString().slice(0, 10);
|
|
27
|
+
logger.log('INFO', `[MetaExecutor] Loading historical rankings for ${prevStr}`);
|
|
28
|
+
rankingsYesterday = await loader.loadRankings(prevStr);
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
// 1. Load Global Dependencies
|
|
20
32
|
const [mappings, rankings, verifications] = await Promise.all([
|
|
21
33
|
loader.loadMappings(),
|
|
@@ -38,11 +50,14 @@ class MetaExecutor {
|
|
|
38
50
|
previousComputedDependencies: previousFetchedDeps,
|
|
39
51
|
config, deps,
|
|
40
52
|
allRankings: rankings,
|
|
53
|
+
allRankingsYesterday: rankingsYesterday, // [FIX] Injected
|
|
41
54
|
allVerifications: verifications
|
|
42
55
|
});
|
|
43
56
|
|
|
44
57
|
try {
|
|
45
58
|
const result = await inst.process(context);
|
|
59
|
+
// Meta results are usually wrapped in a global key or just the result object
|
|
60
|
+
// The structure below implies we store it under the date key
|
|
46
61
|
inst.results = { [dStr]: { global: result } };
|
|
47
62
|
state[c.name] = inst;
|
|
48
63
|
} catch (e) {
|
|
@@ -61,6 +76,18 @@ class MetaExecutor {
|
|
|
61
76
|
const insights = metadata.rootDataDependencies?.includes('insights') ? { today: await loader.loadInsights(dateStr) } : null;
|
|
62
77
|
const social = metadata.rootDataDependencies?.includes('social') ? { today: await loader.loadSocial(dateStr) } : null;
|
|
63
78
|
|
|
79
|
+
// [FIX] Historical support for Batch/OncePerDay execution
|
|
80
|
+
let rankingsYesterday = null;
|
|
81
|
+
if (metadata.isHistorical) {
|
|
82
|
+
const prevDate = new Date(dateStr);
|
|
83
|
+
prevDate.setUTCDate(prevDate.getUTCDate() - 1);
|
|
84
|
+
const prevStr = prevDate.toISOString().slice(0, 10);
|
|
85
|
+
rankingsYesterday = await loader.loadRankings(prevStr);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Load current rankings (often needed for ContextFactory.buildMetaContext)
|
|
89
|
+
const rankings = await loader.loadRankings(dateStr);
|
|
90
|
+
|
|
64
91
|
if (metadata.rootDataDependencies?.includes('price')) {
|
|
65
92
|
logger.log('INFO', `[Executor] Running Batched/Sharded Execution for ${metadata.name}`);
|
|
66
93
|
const shardRefs = await loader.getPriceShardReferences();
|
|
@@ -72,7 +99,9 @@ class MetaExecutor {
|
|
|
72
99
|
const partialContext = ContextFactory.buildMetaContext({
|
|
73
100
|
dateStr, metadata, mappings, insights, socialData: social,
|
|
74
101
|
prices: { history: shardData }, computedDependencies: computedDeps,
|
|
75
|
-
previousComputedDependencies: prevDeps, config, deps
|
|
102
|
+
previousComputedDependencies: prevDeps, config, deps,
|
|
103
|
+
allRankings: rankings,
|
|
104
|
+
allRankingsYesterday: rankingsYesterday
|
|
76
105
|
});
|
|
77
106
|
|
|
78
107
|
await calcInstance.process(partialContext);
|
|
@@ -90,7 +119,9 @@ class MetaExecutor {
|
|
|
90
119
|
const context = ContextFactory.buildMetaContext({
|
|
91
120
|
dateStr, metadata, mappings, insights, socialData: social,
|
|
92
121
|
prices: {}, computedDependencies: computedDeps,
|
|
93
|
-
previousComputedDependencies: prevDeps, config, deps
|
|
122
|
+
previousComputedDependencies: prevDeps, config, deps,
|
|
123
|
+
allRankings: rankings,
|
|
124
|
+
allRankingsYesterday: rankingsYesterday
|
|
94
125
|
});
|
|
95
126
|
const res = await calcInstance.process(context);
|
|
96
127
|
|
|
@@ -102,4 +133,4 @@ class MetaExecutor {
|
|
|
102
133
|
}
|
|
103
134
|
}
|
|
104
135
|
|
|
105
|
-
module.exports = { MetaExecutor };
|
|
136
|
+
module.exports = { MetaExecutor };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* {
|
|
3
3
|
* type: uploaded file
|
|
4
|
-
* fileName:
|
|
4
|
+
* fileName: computation-system/executors/StandardExecutor.js
|
|
5
5
|
* }
|
|
6
6
|
*/
|
|
7
7
|
const { normalizeName, getEarliestDataDates } = require('../utils/utils');
|
|
@@ -141,6 +141,7 @@ class StandardExecutor {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
static async flushBuffer(state, dateStr, passName, config, deps, shardIndexMap, executionStats, mode, skipStatusWrite, isInitialWrite = false) {
|
|
144
|
+
// ... (No changes to flushBuffer)
|
|
144
145
|
const transformedState = {};
|
|
145
146
|
for (const [name, inst] of Object.entries(state)) {
|
|
146
147
|
const rawResult = inst.results || {};
|
|
@@ -178,6 +179,7 @@ class StandardExecutor {
|
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
static mergeReports(successAcc, failureAcc, newResult) {
|
|
182
|
+
// ... (No changes to mergeReports)
|
|
181
183
|
if (!newResult) return;
|
|
182
184
|
for (const [name, update] of Object.entries(newResult.successUpdates)) {
|
|
183
185
|
if (!successAcc[name]) {
|
|
@@ -218,8 +220,15 @@ class StandardExecutor {
|
|
|
218
220
|
const verifications = metadata.rootDataDependencies?.includes('verification') ? await loader.loadVerifications() : null;
|
|
219
221
|
const rankings = metadata.rootDataDependencies?.includes('rankings') ? await loader.loadRankings(dateStr) : null;
|
|
220
222
|
|
|
221
|
-
// [
|
|
222
|
-
|
|
223
|
+
// [FIX] Load Yesterday's Rankings if isHistorical is true
|
|
224
|
+
let yesterdayRankings = null;
|
|
225
|
+
if (metadata.rootDataDependencies?.includes('rankings') && metadata.isHistorical) {
|
|
226
|
+
const prevDate = new Date(dateStr); prevDate.setUTCDate(prevDate.getUTCDate() - 1);
|
|
227
|
+
const prevStr = prevDate.toISOString().slice(0, 10);
|
|
228
|
+
// Assuming CachedDataLoader handles caching for efficiency
|
|
229
|
+
yesterdayRankings = await loader.loadRankings(prevStr);
|
|
230
|
+
}
|
|
231
|
+
|
|
223
232
|
const socialContainer = metadata.rootDataDependencies?.includes('social') ? await loader.loadSocial(dateStr) : null;
|
|
224
233
|
|
|
225
234
|
let chunkSuccess = 0;
|
|
@@ -229,7 +238,6 @@ class StandardExecutor {
|
|
|
229
238
|
const yesterdayPortfolio = yesterdayPortfolioData ? yesterdayPortfolioData[userId] : null;
|
|
230
239
|
const todayHistory = historyData ? historyData[userId] : null;
|
|
231
240
|
|
|
232
|
-
// 2. Identify User Type
|
|
233
241
|
let actualUserType = todayPortfolio._userType;
|
|
234
242
|
if (!actualUserType) {
|
|
235
243
|
if (todayPortfolio.PublicPositions) {
|
|
@@ -240,7 +248,6 @@ class StandardExecutor {
|
|
|
240
248
|
}
|
|
241
249
|
}
|
|
242
250
|
|
|
243
|
-
// 3. Strict User Type Filtering
|
|
244
251
|
if (targetUserType && targetUserType !== 'all') {
|
|
245
252
|
if (targetUserType !== actualUserType) {
|
|
246
253
|
if (stats) stats.skippedUsers++;
|
|
@@ -248,22 +255,19 @@ class StandardExecutor {
|
|
|
248
255
|
}
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
// 4. Resolve Contextual Data
|
|
252
258
|
const userVerification = verifications ? verifications[userId] : null;
|
|
259
|
+
|
|
260
|
+
// [FIX] Extract current AND yesterday's rank entry for this user
|
|
253
261
|
const userRanking = rankings ? (rankings.find(r => String(r.CustomerId) === String(userId)) || null) : null;
|
|
262
|
+
const userRankingYesterday = yesterdayRankings ? (yesterdayRankings.find(r => String(r.CustomerId) === String(userId)) || null) : null;
|
|
254
263
|
|
|
255
|
-
// [CRITICAL FIX] Select Specific Social Data to Prevent Skew
|
|
256
264
|
let effectiveSocialData = null;
|
|
257
265
|
if (socialContainer) {
|
|
258
266
|
if (actualUserType === 'POPULAR_INVESTOR') {
|
|
259
|
-
// PI Route: Only gets PI-specific posts for this user
|
|
260
|
-
// (PIs do not need generic noise usually, or you can merge it if required)
|
|
261
267
|
effectiveSocialData = socialContainer.pi[userId] || {};
|
|
262
268
|
} else if (actualUserType === 'SIGNED_IN_USER') {
|
|
263
|
-
// Signed-In Route: Only gets Signed-In specific posts for this user
|
|
264
269
|
effectiveSocialData = socialContainer.signedIn[userId] || {};
|
|
265
270
|
} else {
|
|
266
|
-
// Normal/Speculator/All Route: Gets Generic Market Posts
|
|
267
271
|
effectiveSocialData = socialContainer.generic || {};
|
|
268
272
|
}
|
|
269
273
|
}
|
|
@@ -271,15 +275,19 @@ class StandardExecutor {
|
|
|
271
275
|
const context = ContextFactory.buildPerUserContext({
|
|
272
276
|
todayPortfolio, yesterdayPortfolio, todayHistory, userId,
|
|
273
277
|
userType: actualUserType, dateStr, metadata, mappings, insights,
|
|
274
|
-
|
|
275
|
-
// Inject the filtered subset
|
|
276
278
|
socialData: effectiveSocialData ? { today: effectiveSocialData } : null,
|
|
277
|
-
|
|
278
279
|
computedDependencies: computedDeps, previousComputedDependencies: prevDeps,
|
|
279
280
|
config, deps,
|
|
280
281
|
verification: userVerification,
|
|
282
|
+
|
|
283
|
+
// [FIX] Pass both ranking entries
|
|
281
284
|
rankings: userRanking,
|
|
285
|
+
yesterdayRankings: userRankingYesterday,
|
|
286
|
+
|
|
287
|
+
// [FIX] Pass both global lists
|
|
282
288
|
allRankings: rankings,
|
|
289
|
+
allRankingsYesterday: yesterdayRankings,
|
|
290
|
+
|
|
283
291
|
allVerifications: verifications
|
|
284
292
|
});
|
|
285
293
|
|
|
@@ -202,90 +202,66 @@ async function handlePopularInvestorUpdate(taskData, config, dependencies) {
|
|
|
202
202
|
logger.log('INFO', `[PI Update] Deep portfolio fetching is disabled. Skipping deep positions for ${username}`);
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
// --- 3. Fetch Trade History (Last 1 Year) with
|
|
205
|
+
// --- 3. Fetch Trade History (Last 1 Year) - Single Page with Large ItemsPerPage ---
|
|
206
206
|
const oneYearAgo = new Date();
|
|
207
207
|
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
|
|
208
208
|
|
|
209
209
|
const historyBaseUrl = ETORO_API_HISTORY_URL || 'https://www.etoro.com/sapi/trade-data-real/history/public/credit/flat';
|
|
210
|
+
const historyUrl = `${historyBaseUrl}?StartTime=${oneYearAgo.toISOString()}&PageNumber=1&ItemsPerPage=30000&PublicHistoryPortfolioFilter=&CID=${cid}&client_request_id=${uuid}`;
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
let
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
let historyRes = null;
|
|
224
|
-
let historySuccess = false;
|
|
225
|
-
|
|
226
|
-
// [CIRCUIT BREAKER] Try proxy only if circuit is not open
|
|
227
|
-
if (shouldTryProxy()) {
|
|
228
|
-
try {
|
|
229
|
-
historyRes = await proxyManager.fetch(historyUrl, requestOptions);
|
|
230
|
-
if (historyRes.ok) {
|
|
231
|
-
historySuccess = true;
|
|
232
|
-
recordProxyOutcome(true);
|
|
233
|
-
} else {
|
|
234
|
-
throw new Error(`Proxy returned non-ok status: ${historyRes.status}`);
|
|
235
|
-
}
|
|
236
|
-
} catch (proxyError) {
|
|
237
|
-
recordProxyOutcome(false);
|
|
238
|
-
logger.log('WARN', `[PI Update] Proxy failed for history page ${page} (${getFailureCount()}/${getMaxFailures()}). Trying direct...`);
|
|
239
|
-
}
|
|
212
|
+
logger.log('INFO', `[PI DEBUG] Fetching History for ${username} URL: ${historyUrl}`);
|
|
213
|
+
|
|
214
|
+
let historyRes = null;
|
|
215
|
+
let historySuccess = false;
|
|
216
|
+
|
|
217
|
+
// [CIRCUIT BREAKER] Try proxy only if circuit is not open
|
|
218
|
+
if (shouldTryProxy()) {
|
|
219
|
+
try {
|
|
220
|
+
historyRes = await proxyManager.fetch(historyUrl, requestOptions);
|
|
221
|
+
if (historyRes.ok) {
|
|
222
|
+
historySuccess = true;
|
|
223
|
+
recordProxyOutcome(true);
|
|
240
224
|
} else {
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Fallback to direct fetch if proxy failed or circuit is open
|
|
245
|
-
if (!historySuccess) {
|
|
246
|
-
try {
|
|
247
|
-
const directFetch = typeof fetch !== 'undefined' ? fetch : require('node-fetch');
|
|
248
|
-
historyRes = await directFetch(historyUrl, requestOptions);
|
|
249
|
-
if (historyRes.ok) {
|
|
250
|
-
historySuccess = true;
|
|
251
|
-
} else {
|
|
252
|
-
throw new Error(`Direct fetch returned non-ok status: ${historyRes.status}`);
|
|
253
|
-
}
|
|
254
|
-
} catch (fetchErr) {
|
|
255
|
-
logger.log('WARN', `[PI Update] Direct fetch also failed for history page ${page}`, fetchErr);
|
|
256
|
-
hasMore = false;
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
225
|
+
throw new Error(`Proxy returned non-ok status: ${historyRes.status}`);
|
|
259
226
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
227
|
+
} catch (proxyError) {
|
|
228
|
+
recordProxyOutcome(false);
|
|
229
|
+
logger.log('WARN', `[PI Update] Proxy failed for history (${getFailureCount()}/${getMaxFailures()}). Trying direct...`);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
// Circuit breaker open, skip proxy
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Fallback to direct fetch if proxy failed or circuit is open
|
|
236
|
+
if (!historySuccess) {
|
|
237
|
+
try {
|
|
238
|
+
const directFetch = typeof fetch !== 'undefined' ? fetch : require('node-fetch');
|
|
239
|
+
historyRes = await directFetch(historyUrl, requestOptions);
|
|
240
|
+
if (historyRes.ok) {
|
|
241
|
+
historySuccess = true;
|
|
272
242
|
} else {
|
|
273
|
-
|
|
274
|
-
hasMore = false;
|
|
243
|
+
throw new Error(`Direct fetch returned non-ok status: ${historyRes.status}`);
|
|
275
244
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
245
|
+
} catch (fetchErr) {
|
|
246
|
+
logger.log('WARN', `[PI Update] Direct fetch also failed for history`, fetchErr);
|
|
247
|
+
historyRes = { ok: false, status: 500 };
|
|
248
|
+
}
|
|
280
249
|
}
|
|
281
250
|
|
|
282
|
-
if (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
251
|
+
if (historySuccess && historyRes.ok) {
|
|
252
|
+
const historyData = await historyRes.json();
|
|
253
|
+
const trades = historyData.PublicHistoryPositions || [];
|
|
254
|
+
|
|
255
|
+
if (trades.length > 0) {
|
|
256
|
+
const historyPayload = {
|
|
257
|
+
PublicHistoryPositions: trades,
|
|
258
|
+
fetchedAt: new Date()
|
|
259
|
+
};
|
|
260
|
+
await batchManager.addToTradingHistoryBatch(String(cid), blockId, today, historyPayload, 'popular_investor');
|
|
261
|
+
logger.log('INFO', `[PI Update] Fetched ${trades.length} trades for ${username}`);
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
logger.log('WARN', `[PI Update] History fetch failed for ${username}. Status: ${historyRes?.status || 'unknown'}`);
|
|
289
265
|
}
|
|
290
266
|
|
|
291
267
|
logger.log('SUCCESS', `[PI Update] Completed full update for ${username}`);
|
|
@@ -389,11 +365,11 @@ async function handleOnDemandUserUpdate(taskData, config, dependencies) {
|
|
|
389
365
|
|
|
390
366
|
await batchManager.addToPortfolioBatch(String(cid), blockId, today, portfolioData, 'signed_in_user');
|
|
391
367
|
|
|
392
|
-
// History Fetch
|
|
368
|
+
// History Fetch - Single Page with Large ItemsPerPage
|
|
393
369
|
const oneYearAgo = new Date();
|
|
394
370
|
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
|
|
395
371
|
const historyBaseUrl = ETORO_API_HISTORY_URL || 'https://www.etoro.com/sapi/trade-data-real/history/public/credit/flat';
|
|
396
|
-
const historyUrl = `${historyBaseUrl}?StartTime=${oneYearAgo.toISOString()}&PageNumber=1&ItemsPerPage=
|
|
372
|
+
const historyUrl = `${historyBaseUrl}?StartTime=${oneYearAgo.toISOString()}&PageNumber=1&ItemsPerPage=30000&PublicHistoryPortfolioFilter=&CID=${cid}&client_request_id=${uuid}`;
|
|
397
373
|
|
|
398
374
|
logger.log('INFO', `[On-Demand DEBUG] Fetching History URL: ${historyUrl}`);
|
|
399
375
|
|