@backtest-kit/sidekick 9.6.0 → 9.7.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.
Files changed (49) hide show
  1. package/README.md +173 -173
  2. package/content/config/source/timeframe_15m.pine +113 -113
  3. package/content/config/source/timeframe_4h.pine +56 -56
  4. package/content/config/symbol.config.cjs +460 -460
  5. package/content/docker/ollama/docker-compose.yaml +34 -34
  6. package/content/docker/ollama/watch.sh +2 -2
  7. package/content/scripts/cache/cache_candles.mjs +47 -47
  8. package/content/scripts/cache/cache_model.mjs +42 -42
  9. package/content/scripts/cache/validate_candles.mjs +46 -46
  10. package/content/scripts/run_timeframe_15m.mjs +77 -77
  11. package/content/scripts/run_timeframe_4h.mjs +68 -68
  12. package/package.json +68 -68
  13. package/scripts/init.mjs +304 -304
  14. package/src/classes/BacktestLowerStopOnBreakevenAction.mjs +17 -17
  15. package/src/classes/BacktestPartialProfitTakingAction.mjs +24 -24
  16. package/src/classes/BacktestPositionMonitorAction.mjs +57 -57
  17. package/src/config/ccxt.mjs +15 -15
  18. package/src/config/params.mjs +1 -1
  19. package/src/config/setup.mjs +45 -45
  20. package/src/config/validate.mjs +14 -14
  21. package/src/enum/ActionName.mjs +5 -5
  22. package/src/enum/ExchangeName.mjs +3 -3
  23. package/src/enum/FrameName.mjs +6 -6
  24. package/src/enum/RiskName.mjs +4 -4
  25. package/src/enum/StrategyName.mjs +3 -3
  26. package/src/index.mjs +6 -6
  27. package/src/logic/action/backtest_lower_stop_on_breakeven.action.mjs +9 -9
  28. package/src/logic/action/backtest_partial_profit_taking.action.mjs +9 -9
  29. package/src/logic/action/backtest_position_monitor.action.mjs +9 -9
  30. package/src/logic/exchange/binance.exchange.mjs +69 -69
  31. package/src/logic/frame/dec_2025.frame.mjs +10 -10
  32. package/src/logic/frame/feb_2024.frame.mjs +10 -10
  33. package/src/logic/frame/nov_2025.frame.mjs +10 -10
  34. package/src/logic/frame/oct_2025.frame.mjs +10 -10
  35. package/src/logic/index.mjs +15 -15
  36. package/src/logic/risk/sl_distance.risk.mjs +32 -32
  37. package/src/logic/risk/tp_distance.risk.mjs +32 -32
  38. package/src/logic/strategy/main.strategy.mjs +48 -48
  39. package/src/main/bootstrap.mjs +52 -52
  40. package/src/math/timeframe_15m.math.mjs +68 -68
  41. package/src/math/timeframe_4h.math.mjs +53 -53
  42. package/src/utils/getArgs.mjs +17 -17
  43. package/template/CLAUDE.mustache +421 -421
  44. package/template/README.mustache +257 -257
  45. package/template/env.mustache +2 -2
  46. package/template/gitignore.mustache +29 -29
  47. package/template/jsconfig.json.mustache +26 -26
  48. package/template/package.mustache +37 -37
  49. 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;
@@ -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
+ });
@@ -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 || "";
@@ -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();
@@ -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
+ })
@@ -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
+ };
@@ -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
+ };
@@ -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
+ });