@tradejs/app 2.0.21 → 3.0.0
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/package.json +8 -8
- package/src/app/actions/backtest.ts +1 -1
- package/src/app/actions/strategies.ts +1 -1
- package/src/app/api/ai/route.ts +13 -6
- package/src/app/api/user/settings/route.ts +48 -28
- package/src/app/components/Shared/OrdersDrawer.tsx +4 -2
- package/src/app/components/Shared/Sidebar/AccountSettingsDrawer.tsx +3 -3
- package/src/app/components/Strategies/RuntimeStrategyCard.presenter.ts +536 -0
- package/src/app/components/Strategies/RuntimeStrategyCard.tsx +16 -1207
- package/src/app/components/Strategies/RuntimeStrategyConfigDrawer.tsx +1 -1
- package/src/app/components/Strategies/RuntimeStrategyStatsDrawer.tsx +677 -0
- package/src/app/components/Strategies/StrategySnapshotCard.details.presenter.ts +38 -0
- package/src/app/components/Strategies/StrategySnapshotCard.diagnostics.presenter.ts +263 -0
- package/src/app/components/Strategies/StrategySnapshotCard.orders.presenter.ts +680 -0
- package/src/app/components/Strategies/StrategySnapshotCard.presenter.ts +119 -0
- package/src/app/components/Strategies/StrategySnapshotCard.ranking.presenter.ts +76 -0
- package/src/app/components/Strategies/StrategySnapshotCard.tsx +13 -1793
- package/src/app/components/Strategies/StrategySnapshotCardDetailsDrawer.tsx +682 -0
- package/src/app/lib/runtimeStrategies.ts +7 -80
- package/src/app/lib/runtimeStrategyContracts.ts +85 -0
- package/src/app/routes/backtest/BacktestJobItem.tsx +275 -0
- package/src/app/routes/backtest/BacktestRunForm.tsx +502 -0
- package/src/app/routes/backtest/page.tsx +16 -1099
- package/src/app/routes/backtest/useBacktestRunsController.ts +441 -0
- package/src/app/routes/strategies/StrategiesPageClient.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Installable Next.js UI for the TradeJS TypeScript framework: dashboards, backtests, charts, and runtime data.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
"@emotion/react": "^11.14.0",
|
|
52
52
|
"@langchain/core": "^1.2.3",
|
|
53
53
|
"@langchain/openai": "^1.5.5",
|
|
54
|
-
"@tradejs/connectors": "^
|
|
55
|
-
"@tradejs/core": "^
|
|
56
|
-
"@tradejs/indicators": "^
|
|
57
|
-
"@tradejs/infra": "^
|
|
58
|
-
"@tradejs/node": "^
|
|
59
|
-
"@tradejs/strategies": "^
|
|
60
|
-
"@tradejs/types": "^
|
|
54
|
+
"@tradejs/connectors": "^3.0.0",
|
|
55
|
+
"@tradejs/core": "^3.0.0",
|
|
56
|
+
"@tradejs/indicators": "^3.0.0",
|
|
57
|
+
"@tradejs/infra": "^3.0.0",
|
|
58
|
+
"@tradejs/node": "^3.0.0",
|
|
59
|
+
"@tradejs/strategies": "^3.0.0",
|
|
60
|
+
"@tradejs/types": "^3.0.0",
|
|
61
61
|
"@types/bcryptjs": "2.4.6",
|
|
62
62
|
"@types/lodash": "4.17.24",
|
|
63
63
|
"@types/node": "24.13.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { API } from '@tradejs/core/api';
|
|
2
2
|
import type { StrategyChartsSnapshotResponse } from '@tradejs/types';
|
|
3
|
-
import type { RuntimeStrategiesResponse } from '#app/lib/
|
|
3
|
+
import type { RuntimeStrategiesResponse } from '#app/lib/runtimeStrategyContracts';
|
|
4
4
|
|
|
5
5
|
const API_PATH = '/api/strategies/runtime';
|
|
6
6
|
const REPLAY_API_PATH = '/api/strategies/replay';
|
package/src/app/api/ai/route.ts
CHANGED
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
} from '@langchain/core/messages';
|
|
8
8
|
import { TTL_1M } from '@tradejs/core/constants';
|
|
9
9
|
import { toJson } from '@tradejs/core/data';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getAiResponseLanguagePromptName,
|
|
12
|
+
normalizeAiResponseLanguage,
|
|
13
|
+
} from '@tradejs/core/aiLanguages';
|
|
14
|
+
import { normalizeAiEndpoint } from '@tradejs/core/aiEndpoints';
|
|
15
|
+
import { normalizeAiModel } from '@tradejs/core/aiModels';
|
|
11
16
|
import { DEFAULT_AI_MODEL, getOpenRouterModelKwargs } from '@tradejs/node/ai';
|
|
12
17
|
import {
|
|
13
18
|
AIChatHistory,
|
|
@@ -98,19 +103,21 @@ const buildMessages = (
|
|
|
98
103
|
|
|
99
104
|
const invokeChatModel = async (messages: BaseMessage[], userName: string) => {
|
|
100
105
|
const settings = await getUserSettings(userName);
|
|
101
|
-
|
|
106
|
+
const endpoint = normalizeAiEndpoint(settings.AI_API_ENDPOINT);
|
|
107
|
+
if (!settings.AI_API_KEY || !endpoint) {
|
|
102
108
|
throw new Error(`AI settings are incomplete for user ${userName}`);
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
const modelKwargs = getOpenRouterModelKwargs(
|
|
111
|
+
const modelKwargs = getOpenRouterModelKwargs(endpoint);
|
|
106
112
|
|
|
107
113
|
const model = new ChatOpenAI({
|
|
108
114
|
temperature: 0.7,
|
|
109
|
-
modelName:
|
|
115
|
+
modelName:
|
|
116
|
+
normalizeAiModel(settings.AI_MODEL, endpoint) || DEFAULT_AI_MODEL,
|
|
110
117
|
apiKey: settings.AI_API_KEY,
|
|
111
118
|
...(Object.keys(modelKwargs).length ? { modelKwargs } : {}),
|
|
112
119
|
configuration: {
|
|
113
|
-
baseURL:
|
|
120
|
+
baseURL: endpoint,
|
|
114
121
|
},
|
|
115
122
|
});
|
|
116
123
|
|
|
@@ -200,7 +207,7 @@ export const POST = async (request: NextRequest) => {
|
|
|
200
207
|
filters,
|
|
201
208
|
message,
|
|
202
209
|
data.slice(-100),
|
|
203
|
-
settings.AI_RESPONSE_LANGUAGE,
|
|
210
|
+
normalizeAiResponseLanguage(settings.AI_RESPONSE_LANGUAGE),
|
|
204
211
|
);
|
|
205
212
|
|
|
206
213
|
const response = await invokeChatModel(chatMessages, userName);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import bcrypt from 'bcryptjs';
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_AI_RESPONSE_LANGUAGE,
|
|
5
|
+
normalizeAiResponseLanguage,
|
|
6
|
+
} from '@tradejs/core/aiLanguages';
|
|
7
|
+
import { normalizeAiEndpoint } from '@tradejs/core/aiEndpoints';
|
|
8
|
+
import { normalizeAiModel } from '@tradejs/core/aiModels';
|
|
6
9
|
import {
|
|
7
10
|
getUserRecord,
|
|
8
11
|
getUserSettings,
|
|
@@ -79,31 +82,46 @@ const maskSecret = (value: string) => {
|
|
|
79
82
|
return `${'*'.repeat(12)}${trimmed.slice(-4) || trimmed}`;
|
|
80
83
|
};
|
|
81
84
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
const normalizeSettingsForResponse = (settings: UserSettings): UserSettings => {
|
|
86
|
+
const endpoint = normalizeAiEndpoint(settings.AI_API_ENDPOINT);
|
|
87
|
+
return {
|
|
88
|
+
...settings,
|
|
89
|
+
AI_API_ENDPOINT: endpoint,
|
|
90
|
+
AI_MODEL: normalizeAiModel(settings.AI_MODEL, endpoint),
|
|
91
|
+
AI_RESPONSE_LANGUAGE:
|
|
92
|
+
normalizeAiResponseLanguage(settings.AI_RESPONSE_LANGUAGE) ||
|
|
93
|
+
DEFAULT_AI_RESPONSE_LANGUAGE,
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const toResponse = (rawSettings: UserSettings) => {
|
|
98
|
+
const settings = normalizeSettingsForResponse(rawSettings);
|
|
99
|
+
return {
|
|
100
|
+
userName: settings.userName,
|
|
101
|
+
settings: {
|
|
102
|
+
bybit: {
|
|
103
|
+
apiKey: maskSecret(settings.BYBIT_API_KEY),
|
|
104
|
+
apiSecret: maskSecret(settings.BYBIT_API_SECRET),
|
|
105
|
+
},
|
|
106
|
+
coinalyze: {
|
|
107
|
+
apiKey: maskSecret(settings.COINALYZE_API_KEY),
|
|
108
|
+
},
|
|
109
|
+
coinmarketcap: {
|
|
110
|
+
apiKey: maskSecret(settings.COINMARKETCAP_API_KEY),
|
|
111
|
+
},
|
|
112
|
+
ai: {
|
|
113
|
+
apiKey: maskSecret(settings.AI_API_KEY),
|
|
114
|
+
apiEndpoint: settings.AI_API_ENDPOINT,
|
|
115
|
+
model: settings.AI_MODEL,
|
|
116
|
+
responseLanguage: settings.AI_RESPONSE_LANGUAGE,
|
|
117
|
+
},
|
|
118
|
+
telegram: {
|
|
119
|
+
botToken: maskSecret(settings.TG_BOT_TOKEN),
|
|
120
|
+
chatId: settings.TG_CHAT_ID,
|
|
121
|
+
},
|
|
104
122
|
},
|
|
105
|
-
}
|
|
106
|
-
}
|
|
123
|
+
};
|
|
124
|
+
};
|
|
107
125
|
|
|
108
126
|
const hasKeys = (patch: Partial<UserRecord>) => Object.keys(patch).length > 0;
|
|
109
127
|
|
|
@@ -198,7 +216,9 @@ export const PATCH = async (request: Request) => {
|
|
|
198
216
|
}
|
|
199
217
|
|
|
200
218
|
if (body.section === 'ai') {
|
|
201
|
-
const currentSettings =
|
|
219
|
+
const currentSettings = normalizeSettingsForResponse(
|
|
220
|
+
await getUserSettings(userName),
|
|
221
|
+
);
|
|
202
222
|
const patch: Partial<UserRecord> = {};
|
|
203
223
|
const apiKey = cleanOptionalText(body.data?.apiKey);
|
|
204
224
|
const apiEndpoint = normalizeAiEndpoint(body.data?.apiEndpoint);
|
|
@@ -25,6 +25,7 @@ export interface OrdersDrawerMetric {
|
|
|
25
25
|
title: string;
|
|
26
26
|
value: ReactNode;
|
|
27
27
|
detail?: ReactNode;
|
|
28
|
+
detailLines?: readonly string[];
|
|
28
29
|
color?: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -339,6 +340,7 @@ const OrderMetric = ({
|
|
|
339
340
|
title,
|
|
340
341
|
value,
|
|
341
342
|
detail,
|
|
343
|
+
detailLines,
|
|
342
344
|
color = 'gray.300',
|
|
343
345
|
}: OrdersDrawerMetric) => (
|
|
344
346
|
<Box minW="0">
|
|
@@ -362,7 +364,7 @@ const OrderMetric = ({
|
|
|
362
364
|
>
|
|
363
365
|
{value}
|
|
364
366
|
</Text>
|
|
365
|
-
{detail ? (
|
|
367
|
+
{detail || detailLines?.length ? (
|
|
366
368
|
<Box
|
|
367
369
|
mt={1}
|
|
368
370
|
color="gray.500"
|
|
@@ -370,7 +372,7 @@ const OrderMetric = ({
|
|
|
370
372
|
lineHeight="1.3"
|
|
371
373
|
wordBreak="break-word"
|
|
372
374
|
>
|
|
373
|
-
{detail}
|
|
375
|
+
{detailLines?.map((line) => <Text key={line}>{line}</Text>) ?? detail}
|
|
374
376
|
</Box>
|
|
375
377
|
) : null}
|
|
376
378
|
</Box>
|
|
@@ -20,18 +20,18 @@ import { FiEdit2, FiSettings } from 'react-icons/fi';
|
|
|
20
20
|
import {
|
|
21
21
|
AI_RESPONSE_LANGUAGE_OPTIONS,
|
|
22
22
|
normalizeAiResponseLanguage,
|
|
23
|
-
} from '@tradejs/
|
|
23
|
+
} from '@tradejs/core/aiLanguages';
|
|
24
24
|
import {
|
|
25
25
|
AI_CUSTOM_ENDPOINT_VALUE,
|
|
26
26
|
AI_ENDPOINT_OPTIONS,
|
|
27
27
|
normalizeAiEndpoint,
|
|
28
|
-
} from '@tradejs/
|
|
28
|
+
} from '@tradejs/core/aiEndpoints';
|
|
29
29
|
import {
|
|
30
30
|
AI_CUSTOM_MODEL_VALUE,
|
|
31
31
|
getAiModelOptionsForEndpoint,
|
|
32
32
|
hasPresetAiModelsForEndpoint,
|
|
33
33
|
normalizeAiModel,
|
|
34
|
-
} from '@tradejs/
|
|
34
|
+
} from '@tradejs/core/aiModels';
|
|
35
35
|
import { toaster } from '#ui';
|
|
36
36
|
import { TradingAccountsPanel } from './TradingAccountsPanel';
|
|
37
37
|
|