@backtest-kit/sidekick 9.0.0 → 9.1.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 +173 -173
- package/content/config/source/timeframe_15m.pine +113 -113
- package/content/config/source/timeframe_4h.pine +56 -56
- package/content/config/symbol.config.cjs +460 -460
- package/content/docker/ollama/docker-compose.yaml +34 -34
- package/content/docker/ollama/watch.sh +2 -2
- package/content/scripts/cache/cache_candles.mjs +47 -47
- package/content/scripts/cache/cache_model.mjs +42 -42
- package/content/scripts/cache/validate_candles.mjs +46 -46
- package/content/scripts/run_timeframe_15m.mjs +77 -77
- package/content/scripts/run_timeframe_4h.mjs +68 -68
- package/package.json +68 -68
- package/scripts/init.mjs +304 -304
- package/src/classes/BacktestLowerStopOnBreakevenAction.mjs +17 -17
- package/src/classes/BacktestPartialProfitTakingAction.mjs +24 -24
- package/src/classes/BacktestPositionMonitorAction.mjs +57 -57
- package/src/config/ccxt.mjs +15 -15
- package/src/config/params.mjs +1 -1
- package/src/config/setup.mjs +45 -45
- package/src/config/validate.mjs +14 -14
- package/src/enum/ActionName.mjs +5 -5
- package/src/enum/ExchangeName.mjs +3 -3
- package/src/enum/FrameName.mjs +6 -6
- package/src/enum/RiskName.mjs +4 -4
- package/src/enum/StrategyName.mjs +3 -3
- package/src/index.mjs +6 -6
- package/src/logic/action/backtest_lower_stop_on_breakeven.action.mjs +9 -9
- package/src/logic/action/backtest_partial_profit_taking.action.mjs +9 -9
- package/src/logic/action/backtest_position_monitor.action.mjs +9 -9
- package/src/logic/exchange/binance.exchange.mjs +69 -69
- package/src/logic/frame/dec_2025.frame.mjs +10 -10
- package/src/logic/frame/feb_2024.frame.mjs +10 -10
- package/src/logic/frame/nov_2025.frame.mjs +10 -10
- package/src/logic/frame/oct_2025.frame.mjs +10 -10
- package/src/logic/index.mjs +15 -15
- package/src/logic/risk/sl_distance.risk.mjs +32 -32
- package/src/logic/risk/tp_distance.risk.mjs +32 -32
- package/src/logic/strategy/main.strategy.mjs +48 -48
- package/src/main/bootstrap.mjs +52 -52
- package/src/math/timeframe_15m.math.mjs +68 -68
- package/src/math/timeframe_4h.math.mjs +53 -53
- package/src/utils/getArgs.mjs +17 -17
- package/template/CLAUDE.mustache +421 -421
- package/template/README.mustache +257 -257
- package/template/env.mustache +2 -2
- package/template/gitignore.mustache +29 -29
- package/template/jsconfig.json.mustache +26 -26
- package/template/package.mustache +37 -37
- package/template/types.mustache +11 -11
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { ActionBase, Constant, commitPartialProfit } from "backtest-kit";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Scale out at Kelly-optimized levels
|
|
5
|
-
* @implements {bt.IPublicAction}
|
|
6
|
-
*/
|
|
7
|
-
export class BacktestPartialProfitTakingAction extends ActionBase {
|
|
8
|
-
/**
|
|
9
|
-
* @param {bt.PartialProfitContract} param0
|
|
10
|
-
*/
|
|
11
|
-
async partialProfitAvailable({ symbol, level }) {
|
|
12
|
-
if (level === Constant.TP_LEVEL3) {
|
|
13
|
-
await commitPartialProfit(symbol, 33);
|
|
14
|
-
}
|
|
15
|
-
if (level === Constant.TP_LEVEL2) {
|
|
16
|
-
await commitPartialProfit(symbol, 33);
|
|
17
|
-
}
|
|
18
|
-
if (level === Constant.TP_LEVEL1) {
|
|
19
|
-
await commitPartialProfit(symbol, 34);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default BacktestPartialProfitTakingAction;
|
|
1
|
+
import { ActionBase, Constant, commitPartialProfit } from "backtest-kit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Scale out at Kelly-optimized levels
|
|
5
|
+
* @implements {bt.IPublicAction}
|
|
6
|
+
*/
|
|
7
|
+
export class BacktestPartialProfitTakingAction extends ActionBase {
|
|
8
|
+
/**
|
|
9
|
+
* @param {bt.PartialProfitContract} param0
|
|
10
|
+
*/
|
|
11
|
+
async partialProfitAvailable({ symbol, level }) {
|
|
12
|
+
if (level === Constant.TP_LEVEL3) {
|
|
13
|
+
await commitPartialProfit(symbol, 33);
|
|
14
|
+
}
|
|
15
|
+
if (level === Constant.TP_LEVEL2) {
|
|
16
|
+
await commitPartialProfit(symbol, 33);
|
|
17
|
+
}
|
|
18
|
+
if (level === Constant.TP_LEVEL1) {
|
|
19
|
+
await commitPartialProfit(symbol, 34);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default BacktestPartialProfitTakingAction;
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { ActionBase } from "backtest-kit";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Monitors position lifecycle and logs open/close events in backtest mode
|
|
5
|
-
* @implements {bt.IPublicAction}
|
|
6
|
-
*/
|
|
7
|
-
export class BacktestPositionMonitorAction extends ActionBase {
|
|
8
|
-
/**
|
|
9
|
-
* @param {bt.IStrategyTickResult} event
|
|
10
|
-
*/
|
|
11
|
-
async signalBacktest(event) {
|
|
12
|
-
switch (event.action) {
|
|
13
|
-
case "scheduled":
|
|
14
|
-
console.log(`[POSITION SCHEDULED] ${event.symbol}`);
|
|
15
|
-
console.log(` Strategy: ${event.strategyName}`);
|
|
16
|
-
console.log(` Current Price: ${event.currentPrice}`);
|
|
17
|
-
console.log(` Entry Price: ${event.signal.priceOpen}`);
|
|
18
|
-
console.log(` Signal ID: ${event.signal.id}`);
|
|
19
|
-
console.log(` Direction: ${event.signal.position}`);
|
|
20
|
-
console.log(` Stop Loss: ${event.signal.priceStopLoss}`);
|
|
21
|
-
console.log(` Take Profit: ${event.signal.priceTakeProfit}`);
|
|
22
|
-
break;
|
|
23
|
-
|
|
24
|
-
case "opened":
|
|
25
|
-
console.log(`[POSITION OPENED] ${event.symbol}`);
|
|
26
|
-
console.log(` Strategy: ${event.strategyName}`);
|
|
27
|
-
console.log(` Entry Price: ${event.currentPrice}`);
|
|
28
|
-
console.log(` Signal ID: ${event.signal.id}`);
|
|
29
|
-
console.log(` Direction: ${event.signal.position}`);
|
|
30
|
-
console.log(` Stop Loss: ${event.signal.priceStopLoss}`);
|
|
31
|
-
console.log(` Take Profit: ${event.signal.priceTakeProfit}`);
|
|
32
|
-
break;
|
|
33
|
-
|
|
34
|
-
case "closed":
|
|
35
|
-
console.log(`[POSITION CLOSED] ${event.symbol}`);
|
|
36
|
-
console.log(` Strategy: ${event.strategyName}`);
|
|
37
|
-
console.log(` Entry Price (adj): ${event.pnl.priceOpen}`);
|
|
38
|
-
console.log(` Exit Price (adj): ${event.pnl.priceClose}`);
|
|
39
|
-
console.log(` Signal ID: ${event.signal.id}`);
|
|
40
|
-
console.log(` Close Reason: ${event.closeReason}`);
|
|
41
|
-
console.log(` PnL: ${event.pnl.pnlPercentage.toFixed(2)}%`);
|
|
42
|
-
console.log(` Win: ${event.pnl.pnlPercentage > 0 ? "YES" : "NO"}`);
|
|
43
|
-
break;
|
|
44
|
-
|
|
45
|
-
case "cancelled":
|
|
46
|
-
console.log(`[POSITION CANCELLED] ${event.symbol}`);
|
|
47
|
-
console.log(` Strategy: ${event.strategyName}`);
|
|
48
|
-
console.log(` Signal ID: ${event.signal.id}`);
|
|
49
|
-
console.log(` Current Price: ${event.currentPrice}`);
|
|
50
|
-
console.log(` Cancel Reason: ${event.reason}`);
|
|
51
|
-
console.log(` Cancelled At: ${new Date(event.closeTimestamp).toISOString()}`);
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export default BacktestPositionMonitorAction;
|
|
1
|
+
import { ActionBase } from "backtest-kit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Monitors position lifecycle and logs open/close events in backtest mode
|
|
5
|
+
* @implements {bt.IPublicAction}
|
|
6
|
+
*/
|
|
7
|
+
export class BacktestPositionMonitorAction extends ActionBase {
|
|
8
|
+
/**
|
|
9
|
+
* @param {bt.IStrategyTickResult} event
|
|
10
|
+
*/
|
|
11
|
+
async signalBacktest(event) {
|
|
12
|
+
switch (event.action) {
|
|
13
|
+
case "scheduled":
|
|
14
|
+
console.log(`[POSITION SCHEDULED] ${event.symbol}`);
|
|
15
|
+
console.log(` Strategy: ${event.strategyName}`);
|
|
16
|
+
console.log(` Current Price: ${event.currentPrice}`);
|
|
17
|
+
console.log(` Entry Price: ${event.signal.priceOpen}`);
|
|
18
|
+
console.log(` Signal ID: ${event.signal.id}`);
|
|
19
|
+
console.log(` Direction: ${event.signal.position}`);
|
|
20
|
+
console.log(` Stop Loss: ${event.signal.priceStopLoss}`);
|
|
21
|
+
console.log(` Take Profit: ${event.signal.priceTakeProfit}`);
|
|
22
|
+
break;
|
|
23
|
+
|
|
24
|
+
case "opened":
|
|
25
|
+
console.log(`[POSITION OPENED] ${event.symbol}`);
|
|
26
|
+
console.log(` Strategy: ${event.strategyName}`);
|
|
27
|
+
console.log(` Entry Price: ${event.currentPrice}`);
|
|
28
|
+
console.log(` Signal ID: ${event.signal.id}`);
|
|
29
|
+
console.log(` Direction: ${event.signal.position}`);
|
|
30
|
+
console.log(` Stop Loss: ${event.signal.priceStopLoss}`);
|
|
31
|
+
console.log(` Take Profit: ${event.signal.priceTakeProfit}`);
|
|
32
|
+
break;
|
|
33
|
+
|
|
34
|
+
case "closed":
|
|
35
|
+
console.log(`[POSITION CLOSED] ${event.symbol}`);
|
|
36
|
+
console.log(` Strategy: ${event.strategyName}`);
|
|
37
|
+
console.log(` Entry Price (adj): ${event.pnl.priceOpen}`);
|
|
38
|
+
console.log(` Exit Price (adj): ${event.pnl.priceClose}`);
|
|
39
|
+
console.log(` Signal ID: ${event.signal.id}`);
|
|
40
|
+
console.log(` Close Reason: ${event.closeReason}`);
|
|
41
|
+
console.log(` PnL: ${event.pnl.pnlPercentage.toFixed(2)}%`);
|
|
42
|
+
console.log(` Win: ${event.pnl.pnlPercentage > 0 ? "YES" : "NO"}`);
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
case "cancelled":
|
|
46
|
+
console.log(`[POSITION CANCELLED] ${event.symbol}`);
|
|
47
|
+
console.log(` Strategy: ${event.strategyName}`);
|
|
48
|
+
console.log(` Signal ID: ${event.signal.id}`);
|
|
49
|
+
console.log(` Current Price: ${event.currentPrice}`);
|
|
50
|
+
console.log(` Cancel Reason: ${event.reason}`);
|
|
51
|
+
console.log(` Cancelled At: ${new Date(event.closeTimestamp).toISOString()}`);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default BacktestPositionMonitorAction;
|
package/src/config/ccxt.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { singleshot } from "functools-kit";
|
|
2
|
-
import ccxt from "ccxt";
|
|
3
|
-
|
|
4
|
-
export const getExchange = singleshot(async () => {
|
|
5
|
-
const exchange = new ccxt.binance({
|
|
6
|
-
options: {
|
|
7
|
-
defaultType: "spot",
|
|
8
|
-
adjustForTimeDifference: true,
|
|
9
|
-
recvWindow: 60000,
|
|
10
|
-
},
|
|
11
|
-
enableRateLimit: true,
|
|
12
|
-
});
|
|
13
|
-
await exchange.loadMarkets();
|
|
14
|
-
return exchange;
|
|
15
|
-
});
|
|
1
|
+
import { singleshot } from "functools-kit";
|
|
2
|
+
import ccxt from "ccxt";
|
|
3
|
+
|
|
4
|
+
export const getExchange = singleshot(async () => {
|
|
5
|
+
const exchange = new ccxt.binance({
|
|
6
|
+
options: {
|
|
7
|
+
defaultType: "spot",
|
|
8
|
+
adjustForTimeDifference: true,
|
|
9
|
+
recvWindow: 60000,
|
|
10
|
+
},
|
|
11
|
+
enableRateLimit: true,
|
|
12
|
+
});
|
|
13
|
+
await exchange.loadMarkets();
|
|
14
|
+
return exchange;
|
|
15
|
+
});
|
package/src/config/params.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CC_OLLAMA_API_KEY = process.env.CC_OLLAMA_API_KEY || "";
|
|
1
|
+
export const CC_OLLAMA_API_KEY = process.env.CC_OLLAMA_API_KEY || "";
|
package/src/config/setup.mjs
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Markdown,
|
|
3
|
-
Report,
|
|
4
|
-
Notification,
|
|
5
|
-
Storage,
|
|
6
|
-
setLogger,
|
|
7
|
-
StorageLive,
|
|
8
|
-
StorageBacktest,
|
|
9
|
-
NotificationLive,
|
|
10
|
-
NotificationBacktest,
|
|
11
|
-
} from "backtest-kit";
|
|
12
|
-
import { serve } from "@backtest-kit/ui";
|
|
13
|
-
import { createLogger } from "pinolog";
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
const logger = createLogger(`backtest-kit.log`);
|
|
17
|
-
setLogger({
|
|
18
|
-
log: (...args) => logger.log(...args),
|
|
19
|
-
debug: (...args) => logger.info(...args),
|
|
20
|
-
info: (...args) => logger.info(...args),
|
|
21
|
-
warn: (...args) => logger.warn(...args),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
Storage.enable();
|
|
27
|
-
Notification.enable();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
Markdown.disable();
|
|
32
|
-
Report.enable();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
{
|
|
36
|
-
StorageLive.usePersist();
|
|
37
|
-
StorageBacktest.usePersist();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
NotificationLive.usePersist();
|
|
42
|
-
NotificationBacktest.usePersist();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
serve();
|
|
1
|
+
import {
|
|
2
|
+
Markdown,
|
|
3
|
+
Report,
|
|
4
|
+
Notification,
|
|
5
|
+
Storage,
|
|
6
|
+
setLogger,
|
|
7
|
+
StorageLive,
|
|
8
|
+
StorageBacktest,
|
|
9
|
+
NotificationLive,
|
|
10
|
+
NotificationBacktest,
|
|
11
|
+
} from "backtest-kit";
|
|
12
|
+
import { serve } from "@backtest-kit/ui";
|
|
13
|
+
import { createLogger } from "pinolog";
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
const logger = createLogger(`backtest-kit.log`);
|
|
17
|
+
setLogger({
|
|
18
|
+
log: (...args) => logger.log(...args),
|
|
19
|
+
debug: (...args) => logger.info(...args),
|
|
20
|
+
info: (...args) => logger.info(...args),
|
|
21
|
+
warn: (...args) => logger.warn(...args),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
{
|
|
26
|
+
Storage.enable();
|
|
27
|
+
Notification.enable();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
{
|
|
31
|
+
Markdown.disable();
|
|
32
|
+
Report.enable();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
{
|
|
36
|
+
StorageLive.usePersist();
|
|
37
|
+
StorageBacktest.usePersist();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
NotificationLive.usePersist();
|
|
42
|
+
NotificationBacktest.usePersist();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
serve();
|
package/src/config/validate.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { validate } from "backtest-kit";
|
|
2
|
-
import ExchangeName from "../enum/ExchangeName.mjs";
|
|
3
|
-
import FrameName from "../enum/FrameName.mjs";
|
|
4
|
-
import RiskName from "../enum/RiskName.mjs";
|
|
5
|
-
import StrategyName from "../enum/StrategyName.mjs";
|
|
6
|
-
import ActionName from "../enum/ActionName.mjs";
|
|
7
|
-
|
|
8
|
-
validate({
|
|
9
|
-
ExchangeName,
|
|
10
|
-
FrameName,
|
|
11
|
-
RiskName,
|
|
12
|
-
StrategyName,
|
|
13
|
-
ActionName,
|
|
14
|
-
})
|
|
1
|
+
import { validate } from "backtest-kit";
|
|
2
|
+
import ExchangeName from "../enum/ExchangeName.mjs";
|
|
3
|
+
import FrameName from "../enum/FrameName.mjs";
|
|
4
|
+
import RiskName from "../enum/RiskName.mjs";
|
|
5
|
+
import StrategyName from "../enum/StrategyName.mjs";
|
|
6
|
+
import ActionName from "../enum/ActionName.mjs";
|
|
7
|
+
|
|
8
|
+
validate({
|
|
9
|
+
ExchangeName,
|
|
10
|
+
FrameName,
|
|
11
|
+
RiskName,
|
|
12
|
+
StrategyName,
|
|
13
|
+
ActionName,
|
|
14
|
+
})
|
package/src/enum/ActionName.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
BacktestPartialProfitTakingAction: "backtest_partial_profit_taking_action",
|
|
3
|
-
BacktestLowerStopOnBreakevenAction: "backtest_lower_stop_on_breakeven_action",
|
|
4
|
-
BacktestPositionMonitorAction: "backtest_position_monitor_action",
|
|
5
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
BacktestPartialProfitTakingAction: "backtest_partial_profit_taking_action",
|
|
3
|
+
BacktestLowerStopOnBreakevenAction: "backtest_lower_stop_on_breakeven_action",
|
|
4
|
+
BacktestPositionMonitorAction: "backtest_position_monitor_action",
|
|
5
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
BinanceExchange: "binance_exchange",
|
|
3
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
BinanceExchange: "binance_exchange",
|
|
3
|
+
};
|
package/src/enum/FrameName.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
February2024: "feb_2024_frame",
|
|
3
|
-
October2025: "oct_2025_frame",
|
|
4
|
-
November2025: "nov_2025_frame",
|
|
5
|
-
December2025: "dec_2025_frame",
|
|
6
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
February2024: "feb_2024_frame",
|
|
3
|
+
October2025: "oct_2025_frame",
|
|
4
|
+
November2025: "nov_2025_frame",
|
|
5
|
+
December2025: "dec_2025_frame",
|
|
6
|
+
};
|
package/src/enum/RiskName.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
TakeProfitDistanceRisk: "tp_distance_risk",
|
|
3
|
-
StopLossDistanceRisk: "sl_distance_risk",
|
|
4
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
TakeProfitDistanceRisk: "tp_distance_risk",
|
|
3
|
+
StopLossDistanceRisk: "sl_distance_risk",
|
|
4
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
MainStrategy: "main_strategy",
|
|
3
|
-
};
|
|
1
|
+
export default {
|
|
2
|
+
MainStrategy: "main_strategy",
|
|
3
|
+
};
|
package/src/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "./config/setup.mjs";
|
|
2
|
-
import "./logic/index.mjs";
|
|
3
|
-
|
|
4
|
-
import "./config/validate.mjs";
|
|
5
|
-
|
|
6
|
-
import "./main/bootstrap.mjs";
|
|
1
|
+
import "./config/setup.mjs";
|
|
2
|
+
import "./logic/index.mjs";
|
|
3
|
+
|
|
4
|
+
import "./config/validate.mjs";
|
|
5
|
+
|
|
6
|
+
import "./main/bootstrap.mjs";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { addActionSchema } from "backtest-kit";
|
|
2
|
-
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
-
import { BacktestLowerStopOnBreakevenAction } from "../../classes/BacktestLowerStopOnBreakevenAction.mjs";
|
|
4
|
-
|
|
5
|
-
addActionSchema({
|
|
6
|
-
actionName: ActionName.BacktestLowerStopOnBreakevenAction,
|
|
7
|
-
handler: BacktestLowerStopOnBreakevenAction,
|
|
8
|
-
note: "Lower trailing-stop by 3 points when breakeven is reached",
|
|
9
|
-
});
|
|
1
|
+
import { addActionSchema } from "backtest-kit";
|
|
2
|
+
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
+
import { BacktestLowerStopOnBreakevenAction } from "../../classes/BacktestLowerStopOnBreakevenAction.mjs";
|
|
4
|
+
|
|
5
|
+
addActionSchema({
|
|
6
|
+
actionName: ActionName.BacktestLowerStopOnBreakevenAction,
|
|
7
|
+
handler: BacktestLowerStopOnBreakevenAction,
|
|
8
|
+
note: "Lower trailing-stop by 3 points when breakeven is reached",
|
|
9
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { addActionSchema } from "backtest-kit";
|
|
2
|
-
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
-
import { BacktestPartialProfitTakingAction } from "../../classes/BacktestPartialProfitTakingAction.mjs";
|
|
4
|
-
|
|
5
|
-
addActionSchema({
|
|
6
|
-
actionName: ActionName.BacktestPartialProfitTakingAction,
|
|
7
|
-
handler: BacktestPartialProfitTakingAction,
|
|
8
|
-
note: "Scale out at Kelly-optimized levels (33%, 33%, 34%)",
|
|
9
|
-
});
|
|
1
|
+
import { addActionSchema } from "backtest-kit";
|
|
2
|
+
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
+
import { BacktestPartialProfitTakingAction } from "../../classes/BacktestPartialProfitTakingAction.mjs";
|
|
4
|
+
|
|
5
|
+
addActionSchema({
|
|
6
|
+
actionName: ActionName.BacktestPartialProfitTakingAction,
|
|
7
|
+
handler: BacktestPartialProfitTakingAction,
|
|
8
|
+
note: "Scale out at Kelly-optimized levels (33%, 33%, 34%)",
|
|
9
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { addActionSchema } from "backtest-kit";
|
|
2
|
-
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
-
import { BacktestPositionMonitorAction } from "../../classes/BacktestPositionMonitorAction.mjs";
|
|
4
|
-
|
|
5
|
-
addActionSchema({
|
|
6
|
-
actionName: ActionName.BacktestPositionMonitorAction,
|
|
7
|
-
handler: BacktestPositionMonitorAction,
|
|
8
|
-
note: "Monitors and logs position lifecycle events (open/close/scheduled)",
|
|
9
|
-
});
|
|
1
|
+
import { addActionSchema } from "backtest-kit";
|
|
2
|
+
import ActionName from "../../enum/ActionName.mjs";
|
|
3
|
+
import { BacktestPositionMonitorAction } from "../../classes/BacktestPositionMonitorAction.mjs";
|
|
4
|
+
|
|
5
|
+
addActionSchema({
|
|
6
|
+
actionName: ActionName.BacktestPositionMonitorAction,
|
|
7
|
+
handler: BacktestPositionMonitorAction,
|
|
8
|
+
note: "Monitors and logs position lifecycle events (open/close/scheduled)",
|
|
9
|
+
});
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import { addExchangeSchema, roundTicks } from "backtest-kit";
|
|
2
|
-
import { getExchange } from "../../config/ccxt.mjs";
|
|
3
|
-
import ExchangeName from "../../enum/ExchangeName.mjs";
|
|
4
|
-
|
|
5
|
-
const MAX_DEPTH_LEVELS = 1_000;
|
|
6
|
-
|
|
7
|
-
addExchangeSchema({
|
|
8
|
-
exchangeName: ExchangeName.BinanceExchange,
|
|
9
|
-
getCandles: async (symbol, interval, since, limit) => {
|
|
10
|
-
const exchange = await getExchange();
|
|
11
|
-
const candles = await exchange.fetchOHLCV(
|
|
12
|
-
symbol,
|
|
13
|
-
interval,
|
|
14
|
-
since.getTime(),
|
|
15
|
-
limit,
|
|
16
|
-
);
|
|
17
|
-
if (
|
|
18
|
-
candles.flatMap((candle) => candle).some((value) => value === undefined)
|
|
19
|
-
) {
|
|
20
|
-
throw new Error("Invalid candles found");
|
|
21
|
-
}
|
|
22
|
-
return candles.map(([timestamp, open, high, low, close, volume]) => ({
|
|
23
|
-
timestamp,
|
|
24
|
-
open,
|
|
25
|
-
high,
|
|
26
|
-
low,
|
|
27
|
-
close,
|
|
28
|
-
volume,
|
|
29
|
-
}));
|
|
30
|
-
},
|
|
31
|
-
formatPrice: async (symbol, price) => {
|
|
32
|
-
const exchange = await getExchange();
|
|
33
|
-
const market = exchange.market(symbol);
|
|
34
|
-
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
35
|
-
if (tickSize !== undefined) {
|
|
36
|
-
return roundTicks(price, tickSize);
|
|
37
|
-
}
|
|
38
|
-
return exchange.priceToPrecision(symbol, price);
|
|
39
|
-
},
|
|
40
|
-
formatQuantity: async (symbol, quantity) => {
|
|
41
|
-
const exchange = await getExchange();
|
|
42
|
-
const market = exchange.market(symbol);
|
|
43
|
-
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
44
|
-
if (stepSize !== undefined) {
|
|
45
|
-
return roundTicks(quantity, stepSize);
|
|
46
|
-
}
|
|
47
|
-
return exchange.amountToPrecision(symbol, quantity);
|
|
48
|
-
},
|
|
49
|
-
getOrderBook: async (symbol) => {
|
|
50
|
-
const exchange = await getExchange();
|
|
51
|
-
const bookData = await exchange.fetchOrderBook(symbol, MAX_DEPTH_LEVELS);
|
|
52
|
-
return {
|
|
53
|
-
symbol,
|
|
54
|
-
asks: bookData.asks.map(([price, quantity]) => ({
|
|
55
|
-
price: String(price),
|
|
56
|
-
quantity: String(quantity),
|
|
57
|
-
})),
|
|
58
|
-
bids: bookData.bids.map(([price, quantity]) => ({
|
|
59
|
-
price: String(price),
|
|
60
|
-
quantity: String(quantity),
|
|
61
|
-
})),
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
callbacks: {
|
|
65
|
-
onCandleData(symbol, interval, since) {
|
|
66
|
-
console.log(`Received candle data for symbol: ${symbol}, interval: ${interval}, since: ${since.toUTCString()}`);
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
});
|
|
1
|
+
import { addExchangeSchema, roundTicks } from "backtest-kit";
|
|
2
|
+
import { getExchange } from "../../config/ccxt.mjs";
|
|
3
|
+
import ExchangeName from "../../enum/ExchangeName.mjs";
|
|
4
|
+
|
|
5
|
+
const MAX_DEPTH_LEVELS = 1_000;
|
|
6
|
+
|
|
7
|
+
addExchangeSchema({
|
|
8
|
+
exchangeName: ExchangeName.BinanceExchange,
|
|
9
|
+
getCandles: async (symbol, interval, since, limit) => {
|
|
10
|
+
const exchange = await getExchange();
|
|
11
|
+
const candles = await exchange.fetchOHLCV(
|
|
12
|
+
symbol,
|
|
13
|
+
interval,
|
|
14
|
+
since.getTime(),
|
|
15
|
+
limit,
|
|
16
|
+
);
|
|
17
|
+
if (
|
|
18
|
+
candles.flatMap((candle) => candle).some((value) => value === undefined)
|
|
19
|
+
) {
|
|
20
|
+
throw new Error("Invalid candles found");
|
|
21
|
+
}
|
|
22
|
+
return candles.map(([timestamp, open, high, low, close, volume]) => ({
|
|
23
|
+
timestamp,
|
|
24
|
+
open,
|
|
25
|
+
high,
|
|
26
|
+
low,
|
|
27
|
+
close,
|
|
28
|
+
volume,
|
|
29
|
+
}));
|
|
30
|
+
},
|
|
31
|
+
formatPrice: async (symbol, price) => {
|
|
32
|
+
const exchange = await getExchange();
|
|
33
|
+
const market = exchange.market(symbol);
|
|
34
|
+
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
35
|
+
if (tickSize !== undefined) {
|
|
36
|
+
return roundTicks(price, tickSize);
|
|
37
|
+
}
|
|
38
|
+
return exchange.priceToPrecision(symbol, price);
|
|
39
|
+
},
|
|
40
|
+
formatQuantity: async (symbol, quantity) => {
|
|
41
|
+
const exchange = await getExchange();
|
|
42
|
+
const market = exchange.market(symbol);
|
|
43
|
+
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
44
|
+
if (stepSize !== undefined) {
|
|
45
|
+
return roundTicks(quantity, stepSize);
|
|
46
|
+
}
|
|
47
|
+
return exchange.amountToPrecision(symbol, quantity);
|
|
48
|
+
},
|
|
49
|
+
getOrderBook: async (symbol) => {
|
|
50
|
+
const exchange = await getExchange();
|
|
51
|
+
const bookData = await exchange.fetchOrderBook(symbol, MAX_DEPTH_LEVELS);
|
|
52
|
+
return {
|
|
53
|
+
symbol,
|
|
54
|
+
asks: bookData.asks.map(([price, quantity]) => ({
|
|
55
|
+
price: String(price),
|
|
56
|
+
quantity: String(quantity),
|
|
57
|
+
})),
|
|
58
|
+
bids: bookData.bids.map(([price, quantity]) => ({
|
|
59
|
+
price: String(price),
|
|
60
|
+
quantity: String(quantity),
|
|
61
|
+
})),
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
callbacks: {
|
|
65
|
+
onCandleData(symbol, interval, since) {
|
|
66
|
+
console.log(`Received candle data for symbol: ${symbol}, interval: ${interval}, since: ${since.toUTCString()}`);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { addFrameSchema } from "backtest-kit";
|
|
2
|
-
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
-
|
|
4
|
-
addFrameSchema({
|
|
5
|
-
frameName: FrameName.December2025,
|
|
6
|
-
interval: "1m",
|
|
7
|
-
startDate: new Date("2025-12-01T00:00:00Z"),
|
|
8
|
-
endDate: new Date("2025-12-31T23:59:59Z"),
|
|
9
|
-
note: "Sideways movement without clear growth or decline",
|
|
10
|
-
});
|
|
1
|
+
import { addFrameSchema } from "backtest-kit";
|
|
2
|
+
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
+
|
|
4
|
+
addFrameSchema({
|
|
5
|
+
frameName: FrameName.December2025,
|
|
6
|
+
interval: "1m",
|
|
7
|
+
startDate: new Date("2025-12-01T00:00:00Z"),
|
|
8
|
+
endDate: new Date("2025-12-31T23:59:59Z"),
|
|
9
|
+
note: "Sideways movement without clear growth or decline",
|
|
10
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { addFrameSchema } from "backtest-kit";
|
|
2
|
-
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
-
|
|
4
|
-
addFrameSchema({
|
|
5
|
-
frameName: FrameName.February2024,
|
|
6
|
-
interval: "1m",
|
|
7
|
-
startDate: new Date("2024-02-01T00:00:00Z"),
|
|
8
|
-
endDate: new Date("2024-02-29T23:59:59Z"),
|
|
9
|
-
note: "Bull run period",
|
|
10
|
-
});
|
|
1
|
+
import { addFrameSchema } from "backtest-kit";
|
|
2
|
+
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
+
|
|
4
|
+
addFrameSchema({
|
|
5
|
+
frameName: FrameName.February2024,
|
|
6
|
+
interval: "1m",
|
|
7
|
+
startDate: new Date("2024-02-01T00:00:00Z"),
|
|
8
|
+
endDate: new Date("2024-02-29T23:59:59Z"),
|
|
9
|
+
note: "Bull run period",
|
|
10
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { addFrameSchema } from "backtest-kit";
|
|
2
|
-
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
-
|
|
4
|
-
addFrameSchema({
|
|
5
|
-
frameName: FrameName.November2025,
|
|
6
|
-
interval: "1m",
|
|
7
|
-
startDate: new Date("2025-11-01T00:00:00Z"),
|
|
8
|
-
endDate: new Date("2025-11-30T23:59:59Z"),
|
|
9
|
-
note: "Sideways movement with overall downtrend and minor bounces",
|
|
10
|
-
});
|
|
1
|
+
import { addFrameSchema } from "backtest-kit";
|
|
2
|
+
import FrameName from "../../enum/FrameName.mjs";
|
|
3
|
+
|
|
4
|
+
addFrameSchema({
|
|
5
|
+
frameName: FrameName.November2025,
|
|
6
|
+
interval: "1m",
|
|
7
|
+
startDate: new Date("2025-11-01T00:00:00Z"),
|
|
8
|
+
endDate: new Date("2025-11-30T23:59:59Z"),
|
|
9
|
+
note: "Sideways movement with overall downtrend and minor bounces",
|
|
10
|
+
});
|