@tradejs/strategies 1.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/README.md +37 -0
- package/dist/chunk-3PN7ZSJJ.mjs +27 -0
- package/dist/chunk-HEBXNMVQ.mjs +48 -0
- package/dist/chunk-MVIV5ZII.mjs +137 -0
- package/dist/chunk-RDK2JK3K.mjs +28 -0
- package/dist/chunk-RYEPHOGL.mjs +28 -0
- package/dist/chunk-ULLCAH5C.mjs +67 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +18471 -0
- package/dist/index.mjs +87 -0
- package/dist/strategy-M3BRWDRR.mjs +377 -0
- package/dist/strategy-Q2QNDZK5.mjs +11262 -0
- package/dist/strategy-UZBWST3G.mjs +156 -0
- package/dist/strategy-Y4SOK6FF.mjs +5816 -0
- package/dist/strategy-ZVNTA6UR.mjs +252 -0
- package/package.json +34 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import {
|
|
2
|
+
maStrategyManifest
|
|
3
|
+
} from "./chunk-RDK2JK3K.mjs";
|
|
4
|
+
import "./chunk-HEBXNMVQ.mjs";
|
|
5
|
+
|
|
6
|
+
// src/MaStrategy/strategy.ts
|
|
7
|
+
import { createStrategyRuntime } from "@tradejs/node/strategies";
|
|
8
|
+
|
|
9
|
+
// src/MaStrategy/config.ts
|
|
10
|
+
var config = {
|
|
11
|
+
ENV: "BACKTEST",
|
|
12
|
+
INTERVAL: "15",
|
|
13
|
+
MAKE_ORDERS: true,
|
|
14
|
+
CLOSE_OPPOSITE_POSITIONS: false,
|
|
15
|
+
BACKTEST_PRICE_MODE: "mid",
|
|
16
|
+
AI_ENABLED: false,
|
|
17
|
+
ML_ENABLED: false,
|
|
18
|
+
ML_THRESHOLD: 0.1,
|
|
19
|
+
MIN_AI_QUALITY: 3,
|
|
20
|
+
FEE_PERCENT: 5e-3,
|
|
21
|
+
MAX_LOSS_VALUE: 10,
|
|
22
|
+
MAX_CORRELATION: 0.45,
|
|
23
|
+
TRADE_COOLDOWN_MS: 0,
|
|
24
|
+
MA_FAST: 21,
|
|
25
|
+
MA_SLOW: 55,
|
|
26
|
+
LONG: {
|
|
27
|
+
enable: true,
|
|
28
|
+
direction: "LONG",
|
|
29
|
+
TP: 2,
|
|
30
|
+
SL: 1,
|
|
31
|
+
minRiskRatio: 1.5
|
|
32
|
+
},
|
|
33
|
+
SHORT: {
|
|
34
|
+
enable: true,
|
|
35
|
+
direction: "SHORT",
|
|
36
|
+
TP: 2,
|
|
37
|
+
SL: 1,
|
|
38
|
+
minRiskRatio: 1.5
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/MaStrategy/core.ts
|
|
43
|
+
import { round } from "@tradejs/core/math";
|
|
44
|
+
|
|
45
|
+
// src/MaStrategy/figures.ts
|
|
46
|
+
var toLinePoints = (candles, values, limit = 120) => {
|
|
47
|
+
const points = [];
|
|
48
|
+
const seriesOffset = Math.max(0, candles.length - values.length);
|
|
49
|
+
const start = Math.max(0, values.length - limit);
|
|
50
|
+
for (let i = start; i < values.length; i += 1) {
|
|
51
|
+
const candle = candles[seriesOffset + i];
|
|
52
|
+
const value = values[i];
|
|
53
|
+
if (!candle || !Number.isFinite(value)) continue;
|
|
54
|
+
points.push({
|
|
55
|
+
timestamp: candle.timestamp,
|
|
56
|
+
value
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return points;
|
|
60
|
+
};
|
|
61
|
+
var buildMaStrategyFigures = ({
|
|
62
|
+
fullData,
|
|
63
|
+
maFast,
|
|
64
|
+
maSlow,
|
|
65
|
+
crossTimestamp,
|
|
66
|
+
crossPrice,
|
|
67
|
+
crossKind
|
|
68
|
+
}) => ({
|
|
69
|
+
lines: [
|
|
70
|
+
{
|
|
71
|
+
id: "ma-fast",
|
|
72
|
+
kind: "ma_fast",
|
|
73
|
+
points: toLinePoints(fullData, maFast),
|
|
74
|
+
color: "#22d3ee",
|
|
75
|
+
width: 2,
|
|
76
|
+
style: "solid"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "ma-slow",
|
|
80
|
+
kind: "ma_slow",
|
|
81
|
+
points: toLinePoints(fullData, maSlow),
|
|
82
|
+
color: "#f59e0b",
|
|
83
|
+
width: 2,
|
|
84
|
+
style: "solid"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
points: [
|
|
88
|
+
{
|
|
89
|
+
id: `ma-cross-${crossTimestamp}`,
|
|
90
|
+
kind: "ma_cross",
|
|
91
|
+
points: [
|
|
92
|
+
{
|
|
93
|
+
timestamp: crossTimestamp,
|
|
94
|
+
value: crossPrice
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
color: crossKind === "bullish" ? "#22c55e" : "#ef4444",
|
|
98
|
+
radius: 4
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// src/MaStrategy/core.ts
|
|
104
|
+
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
105
|
+
var detectCross = (maFast, maSlow) => {
|
|
106
|
+
if (maFast.length < 2 || maSlow.length < 2) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const maFastPrev = maFast[maFast.length - 2];
|
|
110
|
+
const maFastCurrent = maFast[maFast.length - 1];
|
|
111
|
+
const maSlowPrev = maSlow[maSlow.length - 2];
|
|
112
|
+
const maSlowCurrent = maSlow[maSlow.length - 1];
|
|
113
|
+
if (!isFiniteNumber(maFastPrev) || !isFiniteNumber(maFastCurrent) || !isFiniteNumber(maSlowPrev) || !isFiniteNumber(maSlowCurrent)) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
if (maFastPrev <= maSlowPrev && maFastCurrent > maSlowCurrent) {
|
|
117
|
+
return {
|
|
118
|
+
kind: "bullish",
|
|
119
|
+
maFastPrev,
|
|
120
|
+
maFastCurrent,
|
|
121
|
+
maSlowPrev,
|
|
122
|
+
maSlowCurrent
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (maFastPrev >= maSlowPrev && maFastCurrent < maSlowCurrent) {
|
|
126
|
+
return {
|
|
127
|
+
kind: "bearish",
|
|
128
|
+
maFastPrev,
|
|
129
|
+
maFastCurrent,
|
|
130
|
+
maSlowPrev,
|
|
131
|
+
maSlowCurrent
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
};
|
|
136
|
+
var createMaStrategyCore = async ({ config: config2, strategyApi, indicatorsState }) => {
|
|
137
|
+
const {
|
|
138
|
+
ENV,
|
|
139
|
+
FEE_PERCENT,
|
|
140
|
+
MAX_LOSS_VALUE,
|
|
141
|
+
MAX_CORRELATION,
|
|
142
|
+
TRADE_COOLDOWN_MS,
|
|
143
|
+
LONG,
|
|
144
|
+
SHORT
|
|
145
|
+
} = config2;
|
|
146
|
+
const lastTradeController = strategyApi.createLastTradeController({
|
|
147
|
+
enabled: Number(TRADE_COOLDOWN_MS ?? 0) > 0,
|
|
148
|
+
cooldownMs: Number(TRADE_COOLDOWN_MS ?? 0)
|
|
149
|
+
});
|
|
150
|
+
return async () => {
|
|
151
|
+
indicatorsState.onBar();
|
|
152
|
+
const indicators = indicatorsState.snapshot();
|
|
153
|
+
if (!indicators) {
|
|
154
|
+
return strategyApi.skip("NO_INDICATORS");
|
|
155
|
+
}
|
|
156
|
+
const maFast = Array.isArray(indicators.maFast) ? indicators.maFast : [];
|
|
157
|
+
const maSlow = Array.isArray(indicators.maSlow) ? indicators.maSlow : [];
|
|
158
|
+
if (maFast.length < 2 || maSlow.length < 2) {
|
|
159
|
+
return strategyApi.skip("WAIT_MA_DATA");
|
|
160
|
+
}
|
|
161
|
+
const cross = detectCross(maFast, maSlow);
|
|
162
|
+
const position = await strategyApi.getCurrentPosition();
|
|
163
|
+
const positionExists = Boolean(
|
|
164
|
+
position && typeof position.qty === "number" && position.qty > 0
|
|
165
|
+
);
|
|
166
|
+
if (positionExists && position) {
|
|
167
|
+
if (position.direction === "LONG" && cross?.kind === "bearish" || position.direction === "SHORT" && cross?.kind === "bullish") {
|
|
168
|
+
const { currentPrice: currentPrice2, timestamp: timestamp2 } = await strategyApi.getMarketData();
|
|
169
|
+
return {
|
|
170
|
+
kind: "exit",
|
|
171
|
+
code: "CLOSE_BY_OPPOSITE_MA_CROSS",
|
|
172
|
+
closePlan: {
|
|
173
|
+
price: currentPrice2,
|
|
174
|
+
timestamp: timestamp2,
|
|
175
|
+
direction: position.direction
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return strategyApi.skip("POSITION_HELD");
|
|
180
|
+
}
|
|
181
|
+
if (!cross) {
|
|
182
|
+
return strategyApi.skip("NO_CROSS");
|
|
183
|
+
}
|
|
184
|
+
const modeConfig = cross.kind === "bullish" ? LONG : SHORT;
|
|
185
|
+
if (!modeConfig.enable) {
|
|
186
|
+
return strategyApi.skip("STRATEGY_DISABLED");
|
|
187
|
+
}
|
|
188
|
+
const { fullData, timestamp, currentPrice } = await strategyApi.getMarketData();
|
|
189
|
+
if (lastTradeController.isInCooldown(timestamp)) {
|
|
190
|
+
return strategyApi.skip("TRADE_COOLDOWN");
|
|
191
|
+
}
|
|
192
|
+
const { stopLossPrice, takeProfitPrice, riskRatio, qty } = strategyApi.getDirectionalTpSlPrices({
|
|
193
|
+
price: currentPrice,
|
|
194
|
+
direction: modeConfig.direction,
|
|
195
|
+
takeProfitDelta: modeConfig.TP,
|
|
196
|
+
stopLossDelta: modeConfig.SL,
|
|
197
|
+
unit: "percent",
|
|
198
|
+
maxLossValue: MAX_LOSS_VALUE,
|
|
199
|
+
feePercent: Number(FEE_PERCENT ?? 0)
|
|
200
|
+
});
|
|
201
|
+
if (!qty || !Number.isFinite(qty) || qty <= 0) {
|
|
202
|
+
return strategyApi.skip("INVALID_QTY");
|
|
203
|
+
}
|
|
204
|
+
if (riskRatio <= modeConfig.minRiskRatio) {
|
|
205
|
+
return strategyApi.skip(`RISK_RATIO:${round(riskRatio)}`);
|
|
206
|
+
}
|
|
207
|
+
const correlation = indicatorsState.latestNumber("correlation");
|
|
208
|
+
if (ENV !== "BACKTEST" && correlation != null && correlation >= MAX_CORRELATION) {
|
|
209
|
+
return strategyApi.skip(`MAX_CORRELATION:${round(correlation)}`);
|
|
210
|
+
}
|
|
211
|
+
lastTradeController.markTrade(timestamp);
|
|
212
|
+
return strategyApi.entry({
|
|
213
|
+
code: cross.kind === "bullish" ? "MA_BULLISH_CROSS" : "MA_BEARISH_CROSS",
|
|
214
|
+
direction: modeConfig.direction,
|
|
215
|
+
figures: buildMaStrategyFigures({
|
|
216
|
+
fullData,
|
|
217
|
+
maFast,
|
|
218
|
+
maSlow,
|
|
219
|
+
crossTimestamp: timestamp,
|
|
220
|
+
crossPrice: currentPrice,
|
|
221
|
+
crossKind: cross.kind
|
|
222
|
+
}),
|
|
223
|
+
indicators,
|
|
224
|
+
additionalIndicators: {
|
|
225
|
+
crossKind: cross.kind,
|
|
226
|
+
maFastPrev: cross.maFastPrev,
|
|
227
|
+
maFastCurrent: cross.maFastCurrent,
|
|
228
|
+
maSlowPrev: cross.maSlowPrev,
|
|
229
|
+
maSlowCurrent: cross.maSlowCurrent,
|
|
230
|
+
maGap: cross.maFastCurrent - cross.maSlowCurrent,
|
|
231
|
+
correlation
|
|
232
|
+
},
|
|
233
|
+
orderPlan: {
|
|
234
|
+
qty,
|
|
235
|
+
stopLossPrice,
|
|
236
|
+
takeProfits: [{ rate: 1, price: takeProfitPrice }]
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/MaStrategy/strategy.ts
|
|
243
|
+
var MaStrategyCreator = createStrategyRuntime({
|
|
244
|
+
strategyName: "MaStrategy",
|
|
245
|
+
defaults: config,
|
|
246
|
+
createCore: createMaStrategyCore,
|
|
247
|
+
manifest: maStrategyManifest,
|
|
248
|
+
strategyDirectory: __dirname
|
|
249
|
+
});
|
|
250
|
+
export {
|
|
251
|
+
MaStrategyCreator
|
|
252
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tradejs/strategies",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Built-in TradeJS strategy plugin catalog.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@tradejs/core": "^1.0.0",
|
|
20
|
+
"@tradejs/indicators": "^1.0.0",
|
|
21
|
+
"@tradejs/node": "^1.0.0",
|
|
22
|
+
"@tradejs/types": "^1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"tsup": "^8.5.1",
|
|
26
|
+
"typescript": "^5.1"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"typecheck": "tsc -p ./tsconfig.json --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "aleksnick (https://github.com/aleksnick)"
|
|
34
|
+
}
|