@backtest-kit/cli 8.4.2 → 8.5.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 +1692 -1615
- package/build/index.cjs +322 -196
- package/build/index.mjs +322 -196
- package/config/notification.config.mjs +13 -13
- package/config/symbol.config.mjs +460 -460
- package/docker/.env.example +2 -2
- package/docker/content/feb_2026/feb_2026.strategy.ts +11 -11
- package/docker/content/feb_2026/modules/backtest.module.ts +83 -83
- package/docker/docker-compose.yaml +45 -32
- package/docker/package.json +38 -38
- package/docker/tsconfig.json +36 -36
- package/package.json +126 -126
- package/template/average-buy.mustache +22 -22
- package/template/breakeven.mustache +21 -21
- package/template/cancel-scheduled.mustache +14 -14
- package/template/cancelled.mustache +21 -21
- package/template/close-pending.mustache +16 -16
- package/template/closed.mustache +23 -23
- package/template/opened.mustache +22 -22
- package/template/partial-loss.mustache +22 -22
- package/template/partial-profit.mustache +22 -22
- package/template/project/config/symbol.config.ts +460 -460
- package/template/project/package.mustache +28 -28
- package/template/risk.mustache +19 -19
- package/template/scheduled.mustache +22 -22
- package/template/signal-close.mustache +22 -22
- package/template/signal-info.mustache +20 -20
- package/template/signal-open.mustache +22 -22
- package/template/source/CLAUDE.md +160 -160
- package/template/trailing-stop.mustache +21 -21
- package/template/trailing-take.mustache +21 -21
package/docker/.env.example
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
CC_REDIS_HOST=host.docker.internal
|
|
2
|
-
CC_MONGO_CONNECTION_STRING=mongodb://host.docker.internal:27017/backtest-kit?wtimeoutMS=15000
|
|
1
|
+
CC_REDIS_HOST=host.docker.internal
|
|
2
|
+
CC_MONGO_CONNECTION_STRING=mongodb://host.docker.internal:27017/backtest-kit?wtimeoutMS=15000
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
addStrategySchema,
|
|
3
|
-
} from "backtest-kit";
|
|
4
|
-
|
|
5
|
-
addStrategySchema({
|
|
6
|
-
strategyName: "feb_2026_strategy",
|
|
7
|
-
getSignal: async (_symbol, when) => {
|
|
8
|
-
console.log(when);
|
|
9
|
-
return null;
|
|
10
|
-
},
|
|
11
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
addStrategySchema,
|
|
3
|
+
} from "backtest-kit";
|
|
4
|
+
|
|
5
|
+
addStrategySchema({
|
|
6
|
+
strategyName: "feb_2026_strategy",
|
|
7
|
+
getSignal: async (_symbol, when) => {
|
|
8
|
+
console.log(when);
|
|
9
|
+
return null;
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import { addExchangeSchema, addFrameSchema, roundTicks } from "backtest-kit";
|
|
2
|
-
import { singleshot } from "functools-kit";
|
|
3
|
-
import ccxt from "ccxt";
|
|
4
|
-
|
|
5
|
-
const getExchange = singleshot(async () => {
|
|
6
|
-
const exchange = new ccxt.binance({
|
|
7
|
-
options: {
|
|
8
|
-
defaultType: "spot",
|
|
9
|
-
adjustForTimeDifference: true,
|
|
10
|
-
recvWindow: 60000,
|
|
11
|
-
},
|
|
12
|
-
enableRateLimit: true,
|
|
13
|
-
});
|
|
14
|
-
await exchange.loadMarkets();
|
|
15
|
-
return exchange;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
addExchangeSchema({
|
|
19
|
-
exchangeName: "ccxt-exchange",
|
|
20
|
-
getCandles: async (symbol, interval, since, limit) => {
|
|
21
|
-
const exchange = await getExchange();
|
|
22
|
-
const candles = await exchange.fetchOHLCV(
|
|
23
|
-
symbol,
|
|
24
|
-
interval,
|
|
25
|
-
since.getTime(),
|
|
26
|
-
limit,
|
|
27
|
-
);
|
|
28
|
-
return candles.map(([timestamp, open, high, low, close, volume]) => ({
|
|
29
|
-
timestamp,
|
|
30
|
-
open,
|
|
31
|
-
high,
|
|
32
|
-
low,
|
|
33
|
-
close,
|
|
34
|
-
volume,
|
|
35
|
-
}));
|
|
36
|
-
},
|
|
37
|
-
getOrderBook: async (symbol, depth, _from, _to, backtest) => {
|
|
38
|
-
if (backtest) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
"Order book fetching is not supported in backtest mode for the default exchange schema. Please implement it according to your needs.",
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
const exchange = await getExchange();
|
|
44
|
-
const bookData = await exchange.fetchOrderBook(symbol, depth);
|
|
45
|
-
return {
|
|
46
|
-
symbol,
|
|
47
|
-
asks: bookData.asks.map(([price, quantity]) => ({
|
|
48
|
-
price: String(price),
|
|
49
|
-
quantity: String(quantity),
|
|
50
|
-
})),
|
|
51
|
-
bids: bookData.bids.map(([price, quantity]) => ({
|
|
52
|
-
price: String(price),
|
|
53
|
-
quantity: String(quantity),
|
|
54
|
-
})),
|
|
55
|
-
};
|
|
56
|
-
},
|
|
57
|
-
formatPrice: async (symbol, price) => {
|
|
58
|
-
const exchange = await getExchange();
|
|
59
|
-
const market = exchange.market(symbol);
|
|
60
|
-
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
61
|
-
if (tickSize !== undefined) {
|
|
62
|
-
return roundTicks(price, tickSize);
|
|
63
|
-
}
|
|
64
|
-
return exchange.priceToPrecision(symbol, price);
|
|
65
|
-
},
|
|
66
|
-
formatQuantity: async (symbol, quantity) => {
|
|
67
|
-
const exchange = await getExchange();
|
|
68
|
-
const market = exchange.market(symbol);
|
|
69
|
-
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
70
|
-
if (stepSize !== undefined) {
|
|
71
|
-
return roundTicks(quantity, stepSize);
|
|
72
|
-
}
|
|
73
|
-
return exchange.amountToPrecision(symbol, quantity);
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
addFrameSchema({
|
|
78
|
-
frameName: "feb_2026_frame",
|
|
79
|
-
interval: "1m",
|
|
80
|
-
startDate: new Date("2026-02-01T00:00:00Z"),
|
|
81
|
-
endDate: new Date("2026-02-28T23:59:59Z"),
|
|
82
|
-
note: "February 2026",
|
|
83
|
-
});
|
|
1
|
+
import { addExchangeSchema, addFrameSchema, roundTicks } from "backtest-kit";
|
|
2
|
+
import { singleshot } from "functools-kit";
|
|
3
|
+
import ccxt from "ccxt";
|
|
4
|
+
|
|
5
|
+
const getExchange = singleshot(async () => {
|
|
6
|
+
const exchange = new ccxt.binance({
|
|
7
|
+
options: {
|
|
8
|
+
defaultType: "spot",
|
|
9
|
+
adjustForTimeDifference: true,
|
|
10
|
+
recvWindow: 60000,
|
|
11
|
+
},
|
|
12
|
+
enableRateLimit: true,
|
|
13
|
+
});
|
|
14
|
+
await exchange.loadMarkets();
|
|
15
|
+
return exchange;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
addExchangeSchema({
|
|
19
|
+
exchangeName: "ccxt-exchange",
|
|
20
|
+
getCandles: async (symbol, interval, since, limit) => {
|
|
21
|
+
const exchange = await getExchange();
|
|
22
|
+
const candles = await exchange.fetchOHLCV(
|
|
23
|
+
symbol,
|
|
24
|
+
interval,
|
|
25
|
+
since.getTime(),
|
|
26
|
+
limit,
|
|
27
|
+
);
|
|
28
|
+
return candles.map(([timestamp, open, high, low, close, volume]) => ({
|
|
29
|
+
timestamp,
|
|
30
|
+
open,
|
|
31
|
+
high,
|
|
32
|
+
low,
|
|
33
|
+
close,
|
|
34
|
+
volume,
|
|
35
|
+
}));
|
|
36
|
+
},
|
|
37
|
+
getOrderBook: async (symbol, depth, _from, _to, backtest) => {
|
|
38
|
+
if (backtest) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"Order book fetching is not supported in backtest mode for the default exchange schema. Please implement it according to your needs.",
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const exchange = await getExchange();
|
|
44
|
+
const bookData = await exchange.fetchOrderBook(symbol, depth);
|
|
45
|
+
return {
|
|
46
|
+
symbol,
|
|
47
|
+
asks: bookData.asks.map(([price, quantity]) => ({
|
|
48
|
+
price: String(price),
|
|
49
|
+
quantity: String(quantity),
|
|
50
|
+
})),
|
|
51
|
+
bids: bookData.bids.map(([price, quantity]) => ({
|
|
52
|
+
price: String(price),
|
|
53
|
+
quantity: String(quantity),
|
|
54
|
+
})),
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
formatPrice: async (symbol, price) => {
|
|
58
|
+
const exchange = await getExchange();
|
|
59
|
+
const market = exchange.market(symbol);
|
|
60
|
+
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
61
|
+
if (tickSize !== undefined) {
|
|
62
|
+
return roundTicks(price, tickSize);
|
|
63
|
+
}
|
|
64
|
+
return exchange.priceToPrecision(symbol, price);
|
|
65
|
+
},
|
|
66
|
+
formatQuantity: async (symbol, quantity) => {
|
|
67
|
+
const exchange = await getExchange();
|
|
68
|
+
const market = exchange.market(symbol);
|
|
69
|
+
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
70
|
+
if (stepSize !== undefined) {
|
|
71
|
+
return roundTicks(quantity, stepSize);
|
|
72
|
+
}
|
|
73
|
+
return exchange.amountToPrecision(symbol, quantity);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
addFrameSchema({
|
|
78
|
+
frameName: "feb_2026_frame",
|
|
79
|
+
interval: "1m",
|
|
80
|
+
startDate: new Date("2026-02-01T00:00:00Z"),
|
|
81
|
+
endDate: new Date("2026-02-28T23:59:59Z"),
|
|
82
|
+
note: "February 2026",
|
|
83
|
+
});
|
|
@@ -1,32 +1,45 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
backtest:
|
|
5
|
-
image: tripolskypetr/backtest-kit
|
|
6
|
-
# network_mode: host
|
|
7
|
-
extra_hosts:
|
|
8
|
-
- "host.docker.internal:host-gateway"
|
|
9
|
-
container_name: backtest
|
|
10
|
-
ports:
|
|
11
|
-
- "60050:60050"
|
|
12
|
-
restart: unless-stopped
|
|
13
|
-
volumes:
|
|
14
|
-
- ./:/workspace
|
|
15
|
-
working_dir: /workspace
|
|
16
|
-
env_file:
|
|
17
|
-
- .env
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
backtest:
|
|
5
|
+
image: tripolskypetr/backtest-kit
|
|
6
|
+
# network_mode: host
|
|
7
|
+
extra_hosts:
|
|
8
|
+
- "host.docker.internal:host-gateway"
|
|
9
|
+
container_name: backtest
|
|
10
|
+
ports:
|
|
11
|
+
- "60050:60050"
|
|
12
|
+
restart: unless-stopped
|
|
13
|
+
volumes:
|
|
14
|
+
- ./:/workspace
|
|
15
|
+
working_dir: /workspace
|
|
16
|
+
env_file:
|
|
17
|
+
- .env
|
|
18
|
+
environment:
|
|
19
|
+
- MODE
|
|
20
|
+
- STRATEGY_FILE
|
|
21
|
+
- SYMBOL
|
|
22
|
+
- STRATEGY
|
|
23
|
+
- EXCHANGE
|
|
24
|
+
- FRAME
|
|
25
|
+
- UI
|
|
26
|
+
- TELEGRAM
|
|
27
|
+
- VERBOSE
|
|
28
|
+
- NO_CACHE
|
|
29
|
+
- NO_FLUSH
|
|
30
|
+
- ENTRY
|
|
31
|
+
healthcheck:
|
|
32
|
+
test: ["CMD", "curl", "-f", "http://localhost:60050/api/v1/health/health_check"]
|
|
33
|
+
interval: 30s
|
|
34
|
+
timeout: 10s
|
|
35
|
+
retries: 3
|
|
36
|
+
# command:
|
|
37
|
+
# - --backtest
|
|
38
|
+
# - --symbol
|
|
39
|
+
# - BTCUSDT
|
|
40
|
+
# - --strategy
|
|
41
|
+
# - feb_2026_strategy
|
|
42
|
+
# - --exchange
|
|
43
|
+
# - ccxt-exchange
|
|
44
|
+
# - ./content/feb_2026/feb_2026.strategy.ts
|
|
45
|
+
# - --ui
|
package/docker/package.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "example",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "node ./node_modules/@backtest-kit/cli/build/index.mjs",
|
|
8
|
-
"start:debug": "node --inspect-brk ./node_modules/@backtest-kit/cli/build/index.mjs"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [],
|
|
11
|
-
"author": "",
|
|
12
|
-
"license": "ISC",
|
|
13
|
-
"type": "commonjs",
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@types/node": "25.6.0"
|
|
16
|
-
},
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"@backtest-kit/cli": "8.
|
|
19
|
-
"@backtest-kit/graph": "8.
|
|
20
|
-
"@backtest-kit/pinets": "8.
|
|
21
|
-
"@backtest-kit/signals": "8.
|
|
22
|
-
"@backtest-kit/ui": "8.
|
|
23
|
-
"@tavily/core": "0.7.2",
|
|
24
|
-
"@tensorflow/tfjs": "4.22.0",
|
|
25
|
-
"@tensorflow/tfjs-backend-wasm": "4.22.0",
|
|
26
|
-
"@tensorflow/tfjs-core": "4.22.0",
|
|
27
|
-
"agent-swarm-kit": "2.6.0",
|
|
28
|
-
"backtest-kit": "8.
|
|
29
|
-
"dayjs": "1.11.20",
|
|
30
|
-
"functools-kit": "2.3.0",
|
|
31
|
-
"garch": "1.2.3",
|
|
32
|
-
"get-moment-stamp": "1.1.2",
|
|
33
|
-
"jsonrepair": "3.12.0",
|
|
34
|
-
"ollama": "0.6.3",
|
|
35
|
-
"slugify": "1.6.9",
|
|
36
|
-
"volume-anomaly": "1.2.3"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node ./node_modules/@backtest-kit/cli/build/index.mjs",
|
|
8
|
+
"start:debug": "node --inspect-brk ./node_modules/@backtest-kit/cli/build/index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"type": "commonjs",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "25.6.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@backtest-kit/cli": "8.5.0",
|
|
19
|
+
"@backtest-kit/graph": "8.5.0",
|
|
20
|
+
"@backtest-kit/pinets": "8.5.0",
|
|
21
|
+
"@backtest-kit/signals": "8.5.0",
|
|
22
|
+
"@backtest-kit/ui": "8.5.0",
|
|
23
|
+
"@tavily/core": "0.7.2",
|
|
24
|
+
"@tensorflow/tfjs": "4.22.0",
|
|
25
|
+
"@tensorflow/tfjs-backend-wasm": "4.22.0",
|
|
26
|
+
"@tensorflow/tfjs-core": "4.22.0",
|
|
27
|
+
"agent-swarm-kit": "2.6.0",
|
|
28
|
+
"backtest-kit": "8.5.0",
|
|
29
|
+
"dayjs": "1.11.20",
|
|
30
|
+
"functools-kit": "2.3.0",
|
|
31
|
+
"garch": "1.2.3",
|
|
32
|
+
"get-moment-stamp": "1.1.2",
|
|
33
|
+
"jsonrepair": "3.12.0",
|
|
34
|
+
"ollama": "0.6.3",
|
|
35
|
+
"slugify": "1.6.9",
|
|
36
|
+
"volume-anomaly": "1.2.3"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/docker/tsconfig.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"ignoreDeprecations": "6.0",
|
|
4
|
-
"lib": [
|
|
5
|
-
"esnext",
|
|
6
|
-
"dom"
|
|
7
|
-
],
|
|
8
|
-
"types": [
|
|
9
|
-
"node"
|
|
10
|
-
],
|
|
11
|
-
"moduleDetection": "force",
|
|
12
|
-
"target": "ES2020",
|
|
13
|
-
"module": "ESNext",
|
|
14
|
-
"moduleResolution": "bundler",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
"strict": false,
|
|
17
|
-
"downlevelIteration": true,
|
|
18
|
-
"noImplicitAny": false,
|
|
19
|
-
"skipLibCheck": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
"noUnusedLocals": false,
|
|
22
|
-
"noUnusedParameters": false,
|
|
23
|
-
"noPropertyAccessFromIndexSignature": false,
|
|
24
|
-
"paths": {
|
|
25
|
-
"logic": ["./logic/index.ts"],
|
|
26
|
-
"logic/*": ["./logic/*"],
|
|
27
|
-
"utils": ["./utils/index.ts"],
|
|
28
|
-
"utils/*": ["./utils/*"]
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"include": [
|
|
32
|
-
"./logic",
|
|
33
|
-
"./content",
|
|
34
|
-
"./modules",
|
|
35
|
-
],
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"ignoreDeprecations": "6.0",
|
|
4
|
+
"lib": [
|
|
5
|
+
"esnext",
|
|
6
|
+
"dom"
|
|
7
|
+
],
|
|
8
|
+
"types": [
|
|
9
|
+
"node"
|
|
10
|
+
],
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"target": "ES2020",
|
|
13
|
+
"module": "ESNext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"strict": false,
|
|
17
|
+
"downlevelIteration": true,
|
|
18
|
+
"noImplicitAny": false,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUnusedLocals": false,
|
|
22
|
+
"noUnusedParameters": false,
|
|
23
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
24
|
+
"paths": {
|
|
25
|
+
"logic": ["./logic/index.ts"],
|
|
26
|
+
"logic/*": ["./logic/*"],
|
|
27
|
+
"utils": ["./utils/index.ts"],
|
|
28
|
+
"utils/*": ["./utils/*"]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"include": [
|
|
32
|
+
"./logic",
|
|
33
|
+
"./content",
|
|
34
|
+
"./modules",
|
|
35
|
+
],
|
|
36
|
+
}
|