@tradejs/strategies 1.0.5 → 1.0.8

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.
@@ -0,0 +1,163 @@
1
+ // src/TrendShift/adapters/ai.ts
2
+ import { mapAiRuntimeFromConfig } from "@tradejs/core/strategies";
3
+ var getTrendShiftContext = (payload) => {
4
+ const additional = payload.additionalIndicators;
5
+ const raw = additional?.trendShiftContext ?? {};
6
+ const hardBlockReasons = [];
7
+ if (!raw.confirmedFlip) {
8
+ hardBlockReasons.push("unconfirmed_flip");
9
+ }
10
+ if (!raw.flipDistanceOk) {
11
+ hardBlockReasons.push("weak_flip_distance");
12
+ }
13
+ if (raw.coinBiasAligned === false) {
14
+ hardBlockReasons.push("coin_bias_conflict");
15
+ }
16
+ const slopeAbs = Math.abs(raw.avgSlopePct ?? 0);
17
+ const distanceAtrRatio = raw.distanceAtrRatio ?? 0;
18
+ const closeVsAvgPctAbs = Math.abs(raw.closeVsAvgPct ?? 0);
19
+ let deterministicQuality = 3;
20
+ if (hardBlockReasons.length > 0) {
21
+ deterministicQuality = raw.confirmedFlip ? 2 : 1;
22
+ } else if (distanceAtrRatio >= 0.8 && slopeAbs >= 0.09 && closeVsAvgPctAbs >= 0.12) {
23
+ deterministicQuality = 5;
24
+ } else if (distanceAtrRatio >= 0.45 && slopeAbs >= 0.04 && closeVsAvgPctAbs >= 0.05) {
25
+ deterministicQuality = 4;
26
+ }
27
+ return {
28
+ ...raw,
29
+ deterministicQuality,
30
+ approvalAllowedNow: deterministicQuality >= 4,
31
+ hardBlockReasons
32
+ };
33
+ };
34
+ var reasonText = (reason) => {
35
+ switch (reason) {
36
+ case "unconfirmed_flip":
37
+ return "the internal flip is not confirmed yet";
38
+ case "weak_flip_distance":
39
+ return "price moved away from the adaptive average too weakly";
40
+ case "coin_bias_conflict":
41
+ return "coin MA bias conflicts with the flip direction";
42
+ default:
43
+ return reason;
44
+ }
45
+ };
46
+ var trendShiftAiAdapter = {
47
+ buildPayload: ({ signal, basePayload }) => ({
48
+ ...basePayload,
49
+ additionalIndicators: {
50
+ ...basePayload.additionalIndicators,
51
+ trendShiftContext: signal.additionalIndicators?.trendShiftContext
52
+ }
53
+ }),
54
+ postProcessAnalysis: ({ payload, analysis }) => {
55
+ const context = getTrendShiftContext(payload);
56
+ const requestedDirection = analysis.direction === "LONG" || analysis.direction === "SHORT" ? analysis.direction : context.signalDirection;
57
+ if (context.approvalAllowedNow === true && requestedDirection != null) {
58
+ return {
59
+ ...analysis,
60
+ direction: requestedDirection,
61
+ quality: context.deterministicQuality,
62
+ approved: true
63
+ };
64
+ }
65
+ return {
66
+ ...analysis,
67
+ direction: null,
68
+ quality: context.deterministicQuality,
69
+ approved: false,
70
+ rejectReason: context.hardBlockReasons.length > 0 ? context.hardBlockReasons.map(reasonText).join("; ") : "the flip still does not look strong enough for live approval"
71
+ };
72
+ },
73
+ buildHumanPromptAddon: ({ payload }) => {
74
+ const context = getTrendShiftContext(payload);
75
+ return `
76
+ Additional TrendShift context:
77
+ - signalDirection=${context.signalDirection ?? "n/a"}
78
+ - confirmedFlip=${String(context.confirmedFlip)}
79
+ - bullFlip=${String(context.bullFlip)}
80
+ - bearFlip=${String(context.bearFlip)}
81
+ - flipDistanceOk=${String(context.flipDistanceOk)}
82
+ - closeVsAvgPct=${String(context.closeVsAvgPct ?? "n/a")}
83
+ - bandWidthPct=${String(context.bandWidthPct ?? "n/a")}
84
+ - avgSlopePct=${String(context.avgSlopePct ?? "n/a")}
85
+ - distanceAtrRatio=${String(context.distanceAtrRatio ?? "n/a")}
86
+ - coinBias=${context.coinBias ?? "n/a"}
87
+ - coinBiasAligned=${String(context.coinBiasAligned)}
88
+ - deterministicQuality=${context.deterministicQuality}
89
+ - approvalAllowedNow=${context.approvalAllowedNow}
90
+ - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
91
+
92
+ Interpretation rules for TrendShift:
93
+ - This is a trend-state flip strategy, not a forecast of future impulse.
94
+ - If approvalAllowedNow=false, do not describe the signal as a fully confirmed live entry.
95
+ - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
96
+ `.trim();
97
+ },
98
+ mapEntryRuntimeFromConfig: (config2) => mapAiRuntimeFromConfig(
99
+ config2
100
+ )
101
+ };
102
+
103
+ // src/TrendShift/manifest.ts
104
+ var trendShiftManifest = {
105
+ name: "TrendShift",
106
+ aiAdapter: trendShiftAiAdapter
107
+ };
108
+
109
+ // src/TrendShift/config.ts
110
+ var config = {
111
+ ENV: "BACKTEST",
112
+ INTERVAL: "15",
113
+ MAKE_ORDERS: true,
114
+ CLOSE_OPPOSITE_POSITIONS: false,
115
+ BACKTEST_PRICE_MODE: "mid",
116
+ AI_ENABLED: false,
117
+ AI_MODE: "llm",
118
+ ML_ENABLED: false,
119
+ ML_THRESHOLD: 0.1,
120
+ MIN_AI_QUALITY: 3,
121
+ FEE_PERCENT: 5e-3,
122
+ MAX_LOSS_VALUE: 10,
123
+ MA_FAST: 14,
124
+ MA_MEDIUM: 49,
125
+ MA_SLOW: 50,
126
+ OBV_SMA: 10,
127
+ ATR: 14,
128
+ ATR_PCT_SHORT: 7,
129
+ ATR_PCT_LONG: 30,
130
+ BB: 20,
131
+ BB_STD: 2,
132
+ MACD_FAST: 12,
133
+ MACD_SLOW: 26,
134
+ MACD_SIGNAL: 9,
135
+ TRENDSHIFT_MULTIPLICATIVE_FACTOR: 4,
136
+ TRENDSHIFT_SLOPE: 12,
137
+ TRENDSHIFT_ATR_LENGTH: 150,
138
+ TRENDSHIFT_WIDTH_PCT: 75,
139
+ TRENDSHIFT_CONFIRM_FLIP_WITH_CLOSE: true,
140
+ TRENDSHIFT_MIN_FLIP_DISTANCE_ATR: 0.15,
141
+ TRENDSHIFT_EXIT_ON_OPPOSITE_FLIP: true,
142
+ TRENDSHIFT_MAX_FIGURE_POINTS: 180,
143
+ LONG: {
144
+ enable: true,
145
+ direction: "LONG",
146
+ TP: 2.8,
147
+ SL: 1.1,
148
+ minRiskRatio: 1.6
149
+ },
150
+ SHORT: {
151
+ enable: true,
152
+ direction: "SHORT",
153
+ TP: 2.8,
154
+ SL: 1.1,
155
+ minRiskRatio: 1.6
156
+ }
157
+ };
158
+
159
+ export {
160
+ trendShiftAiAdapter,
161
+ trendShiftManifest,
162
+ config
163
+ };