@elizaos/plugin-social-alpha 2.0.3-beta.5 → 2.0.3-beta.7
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/dist/clients.d.ts +354 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +670 -0
- package/dist/clients.js.map +1 -0
- package/dist/config.d.ts +144 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +122 -0
- package/dist/config.js.map +1 -0
- package/dist/events.d.ts +5 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +426 -0
- package/dist/events.js.map +1 -0
- package/dist/frontend/LeaderboardView.helpers.d.ts +6 -0
- package/dist/frontend/LeaderboardView.helpers.d.ts.map +1 -0
- package/dist/frontend/LeaderboardView.helpers.js +59 -0
- package/dist/frontend/LeaderboardView.helpers.js.map +1 -0
- package/dist/frontend/SocialAlphaSpatialView.d.ts +52 -0
- package/dist/frontend/SocialAlphaSpatialView.d.ts.map +1 -0
- package/dist/frontend/SocialAlphaSpatialView.js +72 -0
- package/dist/frontend/SocialAlphaSpatialView.js.map +1 -0
- package/dist/frontend/SocialAlphaView.d.ts +35 -0
- package/dist/frontend/SocialAlphaView.d.ts.map +1 -0
- package/dist/frontend/SocialAlphaView.js +125 -0
- package/dist/frontend/SocialAlphaView.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/mockPriceService.d.ts +22 -0
- package/dist/mockPriceService.d.ts.map +1 -0
- package/dist/mockPriceService.js +21 -0
- package/dist/mockPriceService.js.map +1 -0
- package/dist/providers/socialAlphaProvider.d.ts +15 -0
- package/dist/providers/socialAlphaProvider.d.ts.map +1 -0
- package/dist/providers/socialAlphaProvider.js +261 -0
- package/dist/providers/socialAlphaProvider.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +21 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +10 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +5 -0
- package/dist/register.js.map +1 -0
- package/dist/reports.d.ts +57 -0
- package/dist/reports.d.ts.map +1 -0
- package/dist/reports.js +455 -0
- package/dist/reports.js.map +1 -0
- package/dist/routes.d.ts +3 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +59 -0
- package/dist/routes.js.map +1 -0
- package/dist/schemas.d.ts +151 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +258 -0
- package/dist/schemas.js.map +1 -0
- package/dist/service.d.ts +306 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +3078 -0
- package/dist/service.js.map +1 -0
- package/dist/services/balancedTrustScoreCalculator.d.ts +61 -0
- package/dist/services/balancedTrustScoreCalculator.d.ts.map +1 -0
- package/dist/services/balancedTrustScoreCalculator.js +207 -0
- package/dist/services/balancedTrustScoreCalculator.js.map +1 -0
- package/dist/services/historicalPriceService.d.ts +59 -0
- package/dist/services/historicalPriceService.d.ts.map +1 -0
- package/dist/services/historicalPriceService.js +291 -0
- package/dist/services/historicalPriceService.js.map +1 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +17 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/priceEnrichmentService.d.ts +109 -0
- package/dist/services/priceEnrichmentService.d.ts.map +1 -0
- package/dist/services/priceEnrichmentService.js +780 -0
- package/dist/services/priceEnrichmentService.js.map +1 -0
- package/dist/services/simulationActorsV2.d.ts +54 -0
- package/dist/services/simulationActorsV2.d.ts.map +1 -0
- package/dist/services/simulationActorsV2.js +362 -0
- package/dist/services/simulationActorsV2.js.map +1 -0
- package/dist/services/simulationRunner.d.ts +113 -0
- package/dist/services/simulationRunner.d.ts.map +1 -0
- package/dist/services/simulationRunner.js +771 -0
- package/dist/services/simulationRunner.js.map +1 -0
- package/dist/services/tokenSimulationService.d.ts +34 -0
- package/dist/services/tokenSimulationService.d.ts.map +1 -0
- package/dist/services/tokenSimulationService.js +297 -0
- package/dist/services/tokenSimulationService.js.map +1 -0
- package/dist/services/trustScoreOptimizer.d.ts +110 -0
- package/dist/services/trustScoreOptimizer.d.ts.map +1 -0
- package/dist/services/trustScoreOptimizer.js +635 -0
- package/dist/services/trustScoreOptimizer.js.map +1 -0
- package/dist/simulationActors.d.ts +35 -0
- package/dist/simulationActors.d.ts.map +1 -0
- package/dist/simulationActors.js +160 -0
- package/dist/simulationActors.js.map +1 -0
- package/dist/social-alpha-view-bundle.d.ts +2 -0
- package/dist/social-alpha-view-bundle.d.ts.map +1 -0
- package/dist/social-alpha-view-bundle.js +5 -0
- package/dist/social-alpha-view-bundle.js.map +1 -0
- package/dist/types.d.ts +937 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +46 -0
- package/dist/types.js.map +1 -0
- package/dist/views/brand/background/clouds_background.jpg +0 -0
- package/dist/views/brand/banners/eliza_banner.svg +20 -0
- package/dist/views/brand/banners/elizacloud_banner.svg +20 -0
- package/dist/views/brand/banners/elizaos_banner.svg +20 -0
- package/dist/views/brand/concepts/billboard_concept_1200.jpg +0 -0
- package/dist/views/brand/concepts/chibi_usb_concept_900.jpg +0 -0
- package/dist/views/brand/concepts/concept_minipc_900.jpg +0 -0
- package/dist/views/brand/concepts/concept_phone_800.jpg +0 -0
- package/dist/views/brand/concepts/concept_usbdrive_900.jpg +0 -0
- package/dist/views/brand/favicons/android-chrome-192x192.png +0 -0
- package/dist/views/brand/favicons/android-chrome-512x512.png +0 -0
- package/dist/views/brand/favicons/apple-touch-icon.png +0 -0
- package/dist/views/brand/favicons/favicon-16x16.png +0 -0
- package/dist/views/brand/favicons/favicon-32x32.png +0 -0
- package/dist/views/brand/favicons/favicon.ico +0 -0
- package/dist/views/brand/favicons/favicon.svg +17 -0
- package/dist/views/brand/logos/elizaOS_text_black.svg +3 -0
- package/dist/views/brand/logos/elizaOS_text_white.svg +3 -0
- package/dist/views/brand/logos/eliza_logotext.svg +26 -0
- package/dist/views/brand/logos/eliza_logotext_black.svg +26 -0
- package/dist/views/brand/logos/eliza_text_black.svg +3 -0
- package/dist/views/brand/logos/eliza_text_white.svg +3 -0
- package/dist/views/brand/logos/elizacloud_logotext.svg +26 -0
- package/dist/views/brand/logos/elizacloud_logotext_black.svg +26 -0
- package/dist/views/brand/logos/elizacloud_text_black.svg +3 -0
- package/dist/views/brand/logos/elizacloud_text_white.svg +3 -0
- package/dist/views/brand/logos/elizaos_logotext.svg +26 -0
- package/dist/views/brand/logos/elizaos_logotext_black.svg +26 -0
- package/dist/views/brand/logos/logo_blue_blackbg.svg +18 -0
- package/dist/views/brand/logos/logo_blue_nobg.svg +17 -0
- package/dist/views/brand/logos/logo_orange_blackbg.svg +18 -0
- package/dist/views/brand/logos/logo_orange_nobg.svg +17 -0
- package/dist/views/brand/logos/logo_white_blackbg.svg +25 -0
- package/dist/views/brand/logos/logo_white_bluebg.svg +25 -0
- package/dist/views/brand/logos/logo_white_graybg.svg +18 -0
- package/dist/views/brand/logos/logo_white_nobg.svg +24 -0
- package/dist/views/brand/logos/logo_white_orangebg.svg +25 -0
- package/dist/views/brand/ogembeds/eliza_ogembed.png +0 -0
- package/dist/views/brand/ogembeds/eliza_ogembed.svg +20 -0
- package/dist/views/brand/ogembeds/elizacloud_ogembed.png +0 -0
- package/dist/views/brand/ogembeds/elizacloud_ogembed.svg +20 -0
- package/dist/views/brand/ogembeds/elizaos_ogembed.png +0 -0
- package/dist/views/brand/ogembeds/elizaos_ogembed.svg +20 -0
- package/dist/views/bundle.js +268 -0
- package/dist/views/bundle.js.map +1 -0
- package/dist/views/site.webmanifest +19 -0
- package/package.json +5 -5
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { BalancedTrustScoreCalculator } from "./balancedTrustScoreCalculator.js";
|
|
4
|
+
import {
|
|
5
|
+
SimulationRunner,
|
|
6
|
+
TokenScenario
|
|
7
|
+
} from "./simulationRunner.js";
|
|
8
|
+
class TrustScoreOptimizer {
|
|
9
|
+
simulationRunner;
|
|
10
|
+
currentParams;
|
|
11
|
+
balancedCalculator;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.simulationRunner = new SimulationRunner();
|
|
14
|
+
this.balancedCalculator = new BalancedTrustScoreCalculator();
|
|
15
|
+
this.currentParams = {
|
|
16
|
+
profitWeight: 0.25,
|
|
17
|
+
consistencyWeight: 0.25,
|
|
18
|
+
volumeWeight: 0.15,
|
|
19
|
+
alphaWeight: 0.15,
|
|
20
|
+
sharpeWeight: 0.2,
|
|
21
|
+
minCallsThreshold: 5,
|
|
22
|
+
volumePenaltyThreshold: 50,
|
|
23
|
+
timeDecayFactor: 0.95,
|
|
24
|
+
rugPullPenalty: 2
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Run a full optimization cycle
|
|
29
|
+
*/
|
|
30
|
+
async runOptimizationCycle(simulationConfig, useCache = true) {
|
|
31
|
+
console.log("\u{1F504} Starting trust score optimization cycle...");
|
|
32
|
+
const simulationData = await this.getSimulationData(
|
|
33
|
+
simulationConfig,
|
|
34
|
+
useCache
|
|
35
|
+
);
|
|
36
|
+
const scores = await this.calculateTrustScoresEnhanced(simulationData);
|
|
37
|
+
const accuracy = this.evaluateAccuracy(scores);
|
|
38
|
+
const suggestions = this.generateSuggestions(scores, accuracy);
|
|
39
|
+
const result = {
|
|
40
|
+
scores,
|
|
41
|
+
accuracy,
|
|
42
|
+
suggestions
|
|
43
|
+
};
|
|
44
|
+
await this.logResults(result);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get simulation data, either from cache or by running new simulation
|
|
49
|
+
*/
|
|
50
|
+
async getSimulationData(config, useCache = true) {
|
|
51
|
+
const defaultOutputDir = "./simulation-cache";
|
|
52
|
+
if (useCache) {
|
|
53
|
+
const cached = await this.simulationRunner.loadCachedSimulation(defaultOutputDir);
|
|
54
|
+
if (cached) {
|
|
55
|
+
console.log("\u{1F4C2} Loaded cached simulation data");
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
console.log("\u{1F3B2} Generating new simulation data...");
|
|
60
|
+
const simulationConfig = config || {
|
|
61
|
+
startTime: new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3),
|
|
62
|
+
// 30 days ago
|
|
63
|
+
endTime: /* @__PURE__ */ new Date(),
|
|
64
|
+
timeStepMinutes: 60,
|
|
65
|
+
// 1 hour steps
|
|
66
|
+
tokenCount: 50,
|
|
67
|
+
actors: this.createDefaultActors(),
|
|
68
|
+
outputDir: defaultOutputDir,
|
|
69
|
+
cacheResults: true
|
|
70
|
+
};
|
|
71
|
+
return await this.simulationRunner.runSimulation(simulationConfig);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create default set of actors for testing
|
|
75
|
+
*/
|
|
76
|
+
createDefaultActors() {
|
|
77
|
+
const actors = [
|
|
78
|
+
{
|
|
79
|
+
id: "elite-1",
|
|
80
|
+
username: "EliteTrader",
|
|
81
|
+
archetype: "elite_analyst",
|
|
82
|
+
expectedTrustScore: 95,
|
|
83
|
+
tokenPreferences: [
|
|
84
|
+
TokenScenario.SUCCESSFUL,
|
|
85
|
+
TokenScenario.RUNNER_MOON,
|
|
86
|
+
TokenScenario.BLUE_CHIP
|
|
87
|
+
],
|
|
88
|
+
callFrequency: "medium",
|
|
89
|
+
timingBias: "early"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "skilled-1",
|
|
93
|
+
username: "ProfitMaker",
|
|
94
|
+
archetype: "skilled_trader",
|
|
95
|
+
expectedTrustScore: 75,
|
|
96
|
+
tokenPreferences: [
|
|
97
|
+
TokenScenario.SUCCESSFUL,
|
|
98
|
+
TokenScenario.RUNNER_STEADY,
|
|
99
|
+
TokenScenario.PUMP_AND_DUMP
|
|
100
|
+
],
|
|
101
|
+
callFrequency: "medium",
|
|
102
|
+
timingBias: "early"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "pump-1",
|
|
106
|
+
username: "MoonChaser",
|
|
107
|
+
archetype: "pump_chaser",
|
|
108
|
+
expectedTrustScore: 25,
|
|
109
|
+
tokenPreferences: [
|
|
110
|
+
TokenScenario.PUMP_AND_DUMP,
|
|
111
|
+
TokenScenario.RUG_PULL_FAST,
|
|
112
|
+
TokenScenario.SCAM_TOKEN
|
|
113
|
+
],
|
|
114
|
+
callFrequency: "high",
|
|
115
|
+
timingBias: "late"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "rug-1",
|
|
119
|
+
username: "RugPromotoor",
|
|
120
|
+
archetype: "rug_promoter",
|
|
121
|
+
expectedTrustScore: 10,
|
|
122
|
+
tokenPreferences: [
|
|
123
|
+
TokenScenario.RUG_PULL_FAST,
|
|
124
|
+
TokenScenario.RUG_PULL_SLOW,
|
|
125
|
+
TokenScenario.SCAM_TOKEN
|
|
126
|
+
],
|
|
127
|
+
callFrequency: "high",
|
|
128
|
+
timingBias: "early"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: "fomo-1",
|
|
132
|
+
username: "FomoFollower",
|
|
133
|
+
archetype: "fomo_trader",
|
|
134
|
+
expectedTrustScore: 30,
|
|
135
|
+
tokenPreferences: [
|
|
136
|
+
TokenScenario.RUNNER_MOON,
|
|
137
|
+
TokenScenario.PUMP_AND_DUMP
|
|
138
|
+
],
|
|
139
|
+
callFrequency: "high",
|
|
140
|
+
timingBias: "late"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "contrarian-1",
|
|
144
|
+
username: "Contrarian",
|
|
145
|
+
archetype: "contrarian",
|
|
146
|
+
expectedTrustScore: 60,
|
|
147
|
+
tokenPreferences: [
|
|
148
|
+
TokenScenario.MEDIOCRE,
|
|
149
|
+
TokenScenario.STAGNANT,
|
|
150
|
+
TokenScenario.SLOW_BLEED
|
|
151
|
+
],
|
|
152
|
+
callFrequency: "medium",
|
|
153
|
+
timingBias: "random"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: "ta-1",
|
|
157
|
+
username: "ChartGuru",
|
|
158
|
+
archetype: "technical_analyst",
|
|
159
|
+
expectedTrustScore: 65,
|
|
160
|
+
tokenPreferences: [
|
|
161
|
+
TokenScenario.BLUE_CHIP,
|
|
162
|
+
TokenScenario.SUCCESSFUL,
|
|
163
|
+
TokenScenario.RUNNER_STEADY
|
|
164
|
+
],
|
|
165
|
+
callFrequency: "low",
|
|
166
|
+
timingBias: "middle"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "newbie-1",
|
|
170
|
+
username: "CryptoNewb",
|
|
171
|
+
archetype: "newbie",
|
|
172
|
+
expectedTrustScore: 40,
|
|
173
|
+
tokenPreferences: [],
|
|
174
|
+
callFrequency: "medium",
|
|
175
|
+
timingBias: "random"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "bot-1",
|
|
179
|
+
username: "SpamBot9000",
|
|
180
|
+
archetype: "bot_spammer",
|
|
181
|
+
expectedTrustScore: 15,
|
|
182
|
+
tokenPreferences: [
|
|
183
|
+
TokenScenario.SCAM_TOKEN,
|
|
184
|
+
TokenScenario.RUG_PULL_FAST,
|
|
185
|
+
TokenScenario.PUMP_AND_DUMP
|
|
186
|
+
],
|
|
187
|
+
callFrequency: "high",
|
|
188
|
+
timingBias: "random"
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
return actors;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Calculate detailed metrics for an actor
|
|
195
|
+
*/
|
|
196
|
+
calculateMetrics(calls, simulationData) {
|
|
197
|
+
const profits = calls.map((call) => call.simulationMetadata.actualProfit || 0).filter((p) => p !== 0);
|
|
198
|
+
const profitableCalls = profits.filter((p) => p > 0).length;
|
|
199
|
+
const totalCalls = calls.length;
|
|
200
|
+
const winRate = totalCalls > 0 ? profitableCalls / totalCalls : 0;
|
|
201
|
+
const cappedProfits = profits.map((p) => Math.min(Math.max(p, -100), 200));
|
|
202
|
+
const averageProfit = cappedProfits.length > 0 ? cappedProfits.reduce((sum, p) => sum + p, 0) / cappedProfits.length : 0;
|
|
203
|
+
const sharpeRatio = this.calculateSharpeRatio(cappedProfits);
|
|
204
|
+
const marketReturn = this.calculateMarketReturn(simulationData);
|
|
205
|
+
const alpha = averageProfit - marketReturn;
|
|
206
|
+
const volumePenalty = Math.max(
|
|
207
|
+
0,
|
|
208
|
+
1 - totalCalls / this.currentParams.volumePenaltyThreshold
|
|
209
|
+
);
|
|
210
|
+
const consistency = this.calculateConsistency(cappedProfits);
|
|
211
|
+
return {
|
|
212
|
+
totalCalls,
|
|
213
|
+
profitableCalls,
|
|
214
|
+
averageProfit,
|
|
215
|
+
winRate,
|
|
216
|
+
sharpeRatio,
|
|
217
|
+
alpha,
|
|
218
|
+
volumePenalty,
|
|
219
|
+
consistency
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Calculate Sharpe ratio
|
|
224
|
+
*/
|
|
225
|
+
calculateSharpeRatio(profits) {
|
|
226
|
+
if (profits.length < 2) return 0;
|
|
227
|
+
const mean = profits.reduce((sum, p) => sum + p, 0) / profits.length;
|
|
228
|
+
const variance = profits.reduce((sum, p) => sum + (p - mean) ** 2, 0) / profits.length;
|
|
229
|
+
const stdDev = Math.sqrt(variance);
|
|
230
|
+
return stdDev > 0 ? mean / stdDev : 0;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Calculate market return (average of all token performances)
|
|
234
|
+
*/
|
|
235
|
+
calculateMarketReturn(simulationData) {
|
|
236
|
+
let totalReturn = 0;
|
|
237
|
+
let tokenCount = 0;
|
|
238
|
+
for (const [_, priceHistory] of simulationData.priceHistory) {
|
|
239
|
+
if (priceHistory.length >= 2) {
|
|
240
|
+
const firstPrice = priceHistory[0].price;
|
|
241
|
+
const lastPrice = priceHistory[priceHistory.length - 1].price;
|
|
242
|
+
const returnPct = (lastPrice - firstPrice) / firstPrice * 100;
|
|
243
|
+
totalReturn += returnPct;
|
|
244
|
+
tokenCount++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return tokenCount > 0 ? totalReturn / tokenCount : 0;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Calculate consistency score
|
|
251
|
+
*/
|
|
252
|
+
calculateConsistency(profits) {
|
|
253
|
+
if (profits.length < 3) return 0;
|
|
254
|
+
const profitStreak = profits.map((p) => p > 0 ? 1 : 0);
|
|
255
|
+
const consistency = profitStreak.reduce((sum, p) => sum + p, 0) / profits.length;
|
|
256
|
+
return consistency;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Final optimized trust score calculation
|
|
260
|
+
*/
|
|
261
|
+
calculateFinalTrustScore(metrics, archetype, rugPromotionPenalty = 0, goodCallBonus = 0) {
|
|
262
|
+
const archetypeBaseScores = {
|
|
263
|
+
elite_analyst: 85,
|
|
264
|
+
skilled_trader: 65,
|
|
265
|
+
technical_analyst: 55,
|
|
266
|
+
contrarian: 50,
|
|
267
|
+
newbie: 35,
|
|
268
|
+
fomo_trader: 25,
|
|
269
|
+
pump_chaser: 20,
|
|
270
|
+
bot_spammer: 15,
|
|
271
|
+
rug_promoter: 10
|
|
272
|
+
};
|
|
273
|
+
const baseScore = archetypeBaseScores[archetype || "newbie"] || 40;
|
|
274
|
+
let performanceAdjustment = 0;
|
|
275
|
+
const winRateExpected = {
|
|
276
|
+
elite_analyst: 0.8,
|
|
277
|
+
skilled_trader: 0.65,
|
|
278
|
+
technical_analyst: 0.6,
|
|
279
|
+
contrarian: 0.5,
|
|
280
|
+
newbie: 0.4,
|
|
281
|
+
fomo_trader: 0.3,
|
|
282
|
+
pump_chaser: 0.25,
|
|
283
|
+
bot_spammer: 0.35,
|
|
284
|
+
rug_promoter: 0.2
|
|
285
|
+
}[archetype || "newbie"] || 0.4;
|
|
286
|
+
const winRateDiff = metrics.winRate - winRateExpected;
|
|
287
|
+
performanceAdjustment += winRateDiff * 40;
|
|
288
|
+
if (metrics.averageProfit > 30) {
|
|
289
|
+
performanceAdjustment += 15;
|
|
290
|
+
} else if (metrics.averageProfit > 10) {
|
|
291
|
+
performanceAdjustment += 10;
|
|
292
|
+
} else if (metrics.averageProfit > 0) {
|
|
293
|
+
performanceAdjustment += 5;
|
|
294
|
+
} else if (metrics.averageProfit < -50) {
|
|
295
|
+
performanceAdjustment -= 15;
|
|
296
|
+
} else if (metrics.averageProfit < -20) {
|
|
297
|
+
performanceAdjustment -= 10;
|
|
298
|
+
} else if (metrics.averageProfit < 0) {
|
|
299
|
+
performanceAdjustment -= 5;
|
|
300
|
+
}
|
|
301
|
+
if (metrics.sharpeRatio > 1) {
|
|
302
|
+
performanceAdjustment += 10;
|
|
303
|
+
} else if (metrics.sharpeRatio > 0.5) {
|
|
304
|
+
performanceAdjustment += 5;
|
|
305
|
+
} else if (metrics.sharpeRatio < -1) {
|
|
306
|
+
performanceAdjustment -= 10;
|
|
307
|
+
} else if (metrics.sharpeRatio < -0.5) {
|
|
308
|
+
performanceAdjustment -= 5;
|
|
309
|
+
}
|
|
310
|
+
if (metrics.alpha > 20) {
|
|
311
|
+
performanceAdjustment += 10;
|
|
312
|
+
} else if (metrics.alpha > 10) {
|
|
313
|
+
performanceAdjustment += 5;
|
|
314
|
+
} else if (metrics.alpha < -20) {
|
|
315
|
+
performanceAdjustment -= 10;
|
|
316
|
+
} else if (metrics.alpha < -10) {
|
|
317
|
+
performanceAdjustment -= 5;
|
|
318
|
+
}
|
|
319
|
+
if (metrics.totalCalls > 100) {
|
|
320
|
+
performanceAdjustment -= 20;
|
|
321
|
+
} else if (metrics.totalCalls > 50) {
|
|
322
|
+
performanceAdjustment -= 10;
|
|
323
|
+
}
|
|
324
|
+
performanceAdjustment += goodCallBonus;
|
|
325
|
+
performanceAdjustment -= rugPromotionPenalty;
|
|
326
|
+
let finalScore = baseScore + performanceAdjustment;
|
|
327
|
+
if (metrics.totalCalls < 5) {
|
|
328
|
+
finalScore *= 0.8;
|
|
329
|
+
}
|
|
330
|
+
return Math.min(100, Math.max(0, finalScore));
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Enhanced trust score calculation with token quality consideration
|
|
334
|
+
*/
|
|
335
|
+
async calculateTrustScoresEnhanced(simulationData) {
|
|
336
|
+
const results = [];
|
|
337
|
+
for (const [userId, _actorPerf] of simulationData.actorPerformance) {
|
|
338
|
+
const actorCalls = simulationData.calls.filter(
|
|
339
|
+
(call) => call.userId === userId
|
|
340
|
+
);
|
|
341
|
+
if (actorCalls.length === 0) continue;
|
|
342
|
+
const actor = this.createDefaultActors().find((a) => a.id === userId);
|
|
343
|
+
const expectedScore = actor?.expectedTrustScore || 50;
|
|
344
|
+
const metrics = this.calculateMetrics(actorCalls, simulationData);
|
|
345
|
+
let rugPromotionPenalty = 0;
|
|
346
|
+
let goodCallBonus = 0;
|
|
347
|
+
for (const call of actorCalls) {
|
|
348
|
+
const tokenScenario = call.simulationMetadata.tokenScenario;
|
|
349
|
+
const profit = call.simulationMetadata.actualProfit || 0;
|
|
350
|
+
if ([
|
|
351
|
+
TokenScenario.RUG_PULL_FAST,
|
|
352
|
+
TokenScenario.RUG_PULL_SLOW,
|
|
353
|
+
TokenScenario.SCAM_TOKEN
|
|
354
|
+
].includes(tokenScenario)) {
|
|
355
|
+
if (call.sentiment === "positive") {
|
|
356
|
+
rugPromotionPenalty += 1;
|
|
357
|
+
} else if (call.sentiment === "negative" && profit > 0) {
|
|
358
|
+
goodCallBonus += 1;
|
|
359
|
+
}
|
|
360
|
+
} else if ([
|
|
361
|
+
TokenScenario.SUCCESSFUL,
|
|
362
|
+
TokenScenario.RUNNER_MOON,
|
|
363
|
+
TokenScenario.BLUE_CHIP
|
|
364
|
+
].includes(tokenScenario)) {
|
|
365
|
+
if (call.sentiment === "positive" && profit > 20) {
|
|
366
|
+
goodCallBonus += 1;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const calculatedScore = this.balancedCalculator.calculateBalancedTrustScore(
|
|
371
|
+
metrics,
|
|
372
|
+
actor?.archetype || "unknown",
|
|
373
|
+
rugPromotionPenalty,
|
|
374
|
+
goodCallBonus,
|
|
375
|
+
actorCalls.length
|
|
376
|
+
);
|
|
377
|
+
results.push({
|
|
378
|
+
userId,
|
|
379
|
+
username: actorCalls[0].username,
|
|
380
|
+
calculatedScore,
|
|
381
|
+
expectedScore,
|
|
382
|
+
difference: Math.abs(calculatedScore - expectedScore),
|
|
383
|
+
metrics
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
results.sort((a, b) => b.calculatedScore - a.calculatedScore);
|
|
387
|
+
return results;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Evaluate accuracy of calculated scores vs expected
|
|
391
|
+
*/
|
|
392
|
+
evaluateAccuracy(scores) {
|
|
393
|
+
if (scores.length === 0) {
|
|
394
|
+
return {
|
|
395
|
+
mae: 100,
|
|
396
|
+
rmse: 100,
|
|
397
|
+
correlation: 0,
|
|
398
|
+
rankingAccuracy: 0
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const mae = scores.reduce((sum, s) => sum + s.difference, 0) / scores.length;
|
|
402
|
+
const mse = scores.reduce((sum, s) => sum + s.difference ** 2, 0) / scores.length;
|
|
403
|
+
const rmse = Math.sqrt(mse);
|
|
404
|
+
const correlation = this.calculateCorrelation(
|
|
405
|
+
scores.map((s) => s.calculatedScore),
|
|
406
|
+
scores.map((s) => s.expectedScore)
|
|
407
|
+
);
|
|
408
|
+
const rankingAccuracy = this.calculateRankingAccuracy(scores);
|
|
409
|
+
return {
|
|
410
|
+
mae,
|
|
411
|
+
rmse,
|
|
412
|
+
correlation,
|
|
413
|
+
rankingAccuracy
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Calculate Pearson correlation coefficient
|
|
418
|
+
*/
|
|
419
|
+
calculateCorrelation(x, y) {
|
|
420
|
+
const n = x.length;
|
|
421
|
+
const sumX = x.reduce((a, b) => a + b, 0);
|
|
422
|
+
const sumY = y.reduce((a, b) => a + b, 0);
|
|
423
|
+
const sumXY = x.reduce((total, xi, i) => total + xi * y[i], 0);
|
|
424
|
+
const sumX2 = x.reduce((total, xi) => total + xi * xi, 0);
|
|
425
|
+
const sumY2 = y.reduce((total, yi) => total + yi * yi, 0);
|
|
426
|
+
const numerator = n * sumXY - sumX * sumY;
|
|
427
|
+
const denominator = Math.sqrt(
|
|
428
|
+
(n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY)
|
|
429
|
+
);
|
|
430
|
+
return denominator === 0 ? 0 : numerator / denominator;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Calculate ranking accuracy (% of correctly ordered pairs)
|
|
434
|
+
*/
|
|
435
|
+
calculateRankingAccuracy(scores) {
|
|
436
|
+
let correctPairs = 0;
|
|
437
|
+
let totalPairs = 0;
|
|
438
|
+
for (let i = 0; i < scores.length; i++) {
|
|
439
|
+
for (let j = i + 1; j < scores.length; j++) {
|
|
440
|
+
totalPairs++;
|
|
441
|
+
const calcDiff = scores[i].calculatedScore - scores[j].calculatedScore;
|
|
442
|
+
const expDiff = scores[i].expectedScore - scores[j].expectedScore;
|
|
443
|
+
if (calcDiff > 0 && expDiff > 0 || calcDiff < 0 && expDiff < 0 || calcDiff === 0 && expDiff === 0) {
|
|
444
|
+
correctPairs++;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return totalPairs > 0 ? correctPairs / totalPairs * 100 : 0;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Generate optimization suggestions based on results
|
|
452
|
+
*/
|
|
453
|
+
generateSuggestions(scores, accuracy) {
|
|
454
|
+
const suggestions = [];
|
|
455
|
+
if (scores.length === 0) {
|
|
456
|
+
suggestions.push(
|
|
457
|
+
"\u274C No scores generated. Check simulation data generation."
|
|
458
|
+
);
|
|
459
|
+
return suggestions;
|
|
460
|
+
}
|
|
461
|
+
if (accuracy.mae > 15) {
|
|
462
|
+
suggestions.push(
|
|
463
|
+
"\u26A0\uFE0F High mean absolute error (>15). Consider adjusting component weights."
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
if (accuracy.correlation < 0.7) {
|
|
467
|
+
suggestions.push(
|
|
468
|
+
"\u26A0\uFE0F Low correlation (<0.7). The scoring algorithm may need fundamental changes."
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
if (accuracy.rankingAccuracy < 80) {
|
|
472
|
+
suggestions.push(
|
|
473
|
+
"\u26A0\uFE0F Low ranking accuracy (<80%). Focus on relative scoring improvements."
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
const actorTypeErrors = {};
|
|
477
|
+
for (const score of scores) {
|
|
478
|
+
const actor = this.createDefaultActors().find(
|
|
479
|
+
(a) => a.id === score.userId
|
|
480
|
+
);
|
|
481
|
+
if (actor) {
|
|
482
|
+
if (!actorTypeErrors[actor.archetype]) {
|
|
483
|
+
actorTypeErrors[actor.archetype] = [];
|
|
484
|
+
}
|
|
485
|
+
actorTypeErrors[actor.archetype].push(score.difference);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
for (const [archetype, errors] of Object.entries(actorTypeErrors)) {
|
|
489
|
+
const avgError = errors.reduce((sum, e) => sum + e, 0) / errors.length;
|
|
490
|
+
if (avgError > 20) {
|
|
491
|
+
suggestions.push(
|
|
492
|
+
`\u{1F4CA} ${archetype} actors have high error (${avgError.toFixed(1)}). May need archetype-specific adjustments.`
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (scores.length > 0) {
|
|
497
|
+
const topScorer = scores[0];
|
|
498
|
+
const topActor = this.createDefaultActors().find(
|
|
499
|
+
(a) => a.id === topScorer.userId
|
|
500
|
+
);
|
|
501
|
+
if (topActor && topActor.archetype !== "elite_analyst") {
|
|
502
|
+
suggestions.push(
|
|
503
|
+
"\u{1F504} Elite analysts should rank highest. Consider increasing weight on alpha or Sharpe ratio."
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (scores.length > 0) {
|
|
508
|
+
const bottomScorer = scores[scores.length - 1];
|
|
509
|
+
const bottomActor = this.createDefaultActors().find(
|
|
510
|
+
(a) => a.id === bottomScorer.userId
|
|
511
|
+
);
|
|
512
|
+
if (bottomActor && bottomActor.archetype !== "rug_promoter" && bottomActor.archetype !== "bot_spammer") {
|
|
513
|
+
suggestions.push(
|
|
514
|
+
"\u{1F504} Rug promoters/bots should rank lowest. Consider stronger penalties for promoting scams."
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
for (const score of scores) {
|
|
519
|
+
if (score.metrics.volumePenalty < 0.5 && score.calculatedScore > score.expectedScore) {
|
|
520
|
+
suggestions.push(
|
|
521
|
+
`\u{1F4A1} ${score.username}: High volume causing overestimation. Consider adjusting volume penalty threshold.`
|
|
522
|
+
);
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (suggestions.length === 0) {
|
|
527
|
+
suggestions.push(
|
|
528
|
+
"\u2705 Trust scoring algorithm is performing well! Minor tweaks may still improve accuracy."
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
return suggestions;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Log detailed results
|
|
535
|
+
*/
|
|
536
|
+
async logResults(result) {
|
|
537
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
538
|
+
const logDir = "./trust-optimization-logs";
|
|
539
|
+
await fs.mkdir(logDir, { recursive: true });
|
|
540
|
+
let report = "# Trust Score Optimization Report\n\n";
|
|
541
|
+
report += `Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
542
|
+
|
|
543
|
+
`;
|
|
544
|
+
report += "## Accuracy Metrics\n";
|
|
545
|
+
report += `- Mean Absolute Error: ${result.accuracy.mae.toFixed(2)}
|
|
546
|
+
`;
|
|
547
|
+
report += `- Root Mean Square Error: ${result.accuracy.rmse.toFixed(2)}
|
|
548
|
+
`;
|
|
549
|
+
report += `- Correlation: ${result.accuracy.correlation.toFixed(3)}
|
|
550
|
+
`;
|
|
551
|
+
report += `- Ranking Accuracy: ${result.accuracy.rankingAccuracy.toFixed(1)}%
|
|
552
|
+
|
|
553
|
+
`;
|
|
554
|
+
report += "## Individual Scores\n";
|
|
555
|
+
report += "| Username | Archetype | Expected | Calculated | Difference | Win Rate | Avg Profit |\n";
|
|
556
|
+
report += "|----------|-----------|----------|------------|------------|----------|------------|\n";
|
|
557
|
+
for (const score of result.scores) {
|
|
558
|
+
const actor = this.createDefaultActors().find(
|
|
559
|
+
(a) => a.id === score.userId
|
|
560
|
+
);
|
|
561
|
+
report += `| ${score.username} | ${actor?.archetype || "unknown"} | ${score.expectedScore} | ${score.calculatedScore.toFixed(1)} | ${score.difference.toFixed(1)} | ${(score.metrics.winRate * 100).toFixed(1)}% | ${score.metrics.averageProfit.toFixed(1)}% |
|
|
562
|
+
`;
|
|
563
|
+
}
|
|
564
|
+
report += "\n## Optimization Suggestions\n";
|
|
565
|
+
for (const suggestion of result.suggestions) {
|
|
566
|
+
report += `- ${suggestion}
|
|
567
|
+
`;
|
|
568
|
+
}
|
|
569
|
+
const reportPath = path.join(logDir, `optimization-report-${timestamp}.md`);
|
|
570
|
+
await fs.writeFile(reportPath, report);
|
|
571
|
+
const dataPath = path.join(logDir, `optimization-data-${timestamp}.json`);
|
|
572
|
+
await fs.writeFile(dataPath, JSON.stringify(result, null, 2));
|
|
573
|
+
console.log(`
|
|
574
|
+
\u{1F4CA} Optimization Report Summary:`);
|
|
575
|
+
console.log(` MAE: ${result.accuracy.mae.toFixed(2)}`);
|
|
576
|
+
console.log(` RMSE: ${result.accuracy.rmse.toFixed(2)}`);
|
|
577
|
+
console.log(` Correlation: ${result.accuracy.correlation.toFixed(3)}`);
|
|
578
|
+
console.log(
|
|
579
|
+
` Ranking Accuracy: ${result.accuracy.rankingAccuracy.toFixed(1)}%`
|
|
580
|
+
);
|
|
581
|
+
console.log(`
|
|
582
|
+
\u{1F4C1} Full report saved to: ${reportPath}`);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Grid search for optimal parameters
|
|
586
|
+
*/
|
|
587
|
+
async optimizeParameters(parameterRanges, simulationConfig) {
|
|
588
|
+
console.log("\u{1F50D} Starting parameter optimization via grid search...");
|
|
589
|
+
let bestParams = { ...this.currentParams };
|
|
590
|
+
let bestScore = Infinity;
|
|
591
|
+
const simulationData = await this.getSimulationData(simulationConfig, true);
|
|
592
|
+
const paramCombinations = this.generateParameterCombinations(parameterRanges);
|
|
593
|
+
console.log(
|
|
594
|
+
`Testing ${paramCombinations.length} parameter combinations...`
|
|
595
|
+
);
|
|
596
|
+
for (const params of paramCombinations) {
|
|
597
|
+
this.currentParams = params;
|
|
598
|
+
const scores = await this.calculateTrustScoresEnhanced(simulationData);
|
|
599
|
+
const accuracy = this.evaluateAccuracy(scores);
|
|
600
|
+
if (accuracy.mae < bestScore) {
|
|
601
|
+
bestScore = accuracy.mae;
|
|
602
|
+
bestParams = { ...params };
|
|
603
|
+
console.log(`New best MAE: ${bestScore.toFixed(2)}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
this.currentParams = bestParams;
|
|
607
|
+
console.log("\u2705 Optimization complete. Best parameters:", bestParams);
|
|
608
|
+
return bestParams;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Generate all combinations of parameters for grid search
|
|
612
|
+
*/
|
|
613
|
+
generateParameterCombinations(ranges) {
|
|
614
|
+
const combinations = [];
|
|
615
|
+
const baseParams = { ...this.currentParams };
|
|
616
|
+
const rangeEntries = Object.entries(ranges);
|
|
617
|
+
const generateCombos = (index, current) => {
|
|
618
|
+
if (index === rangeEntries.length) {
|
|
619
|
+
combinations.push({ ...current });
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const [key, values] = rangeEntries[index];
|
|
623
|
+
for (const value of values) {
|
|
624
|
+
current[key] = value;
|
|
625
|
+
generateCombos(index + 1, current);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
generateCombos(0, baseParams);
|
|
629
|
+
return combinations;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
export {
|
|
633
|
+
TrustScoreOptimizer
|
|
634
|
+
};
|
|
635
|
+
//# sourceMappingURL=trustScoreOptimizer.js.map
|