backtest-kit 1.1.4 โ 1.1.5
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 +88 -35
- package/build/index.cjs +191 -0
- package/build/index.mjs +188 -1
- package/package.json +1 -1
- package/types.d.ts +172 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
- ๐ **Markdown Reports** - Auto-generated trading reports with statistics (win rate, avg PNL)
|
|
22
22
|
- ๐ **Graceful Shutdown** - Live.background() waits for open positions to close before stopping
|
|
23
23
|
- ๐ **Strategy Dependency Injection** - addStrategy() enables DI pattern for trading strategies
|
|
24
|
+
- ๐ **Schema Reflection API** - listExchanges(), listStrategies(), listFrames() for runtime introspection
|
|
24
25
|
- ๐งช **Comprehensive Test Coverage** - 30+ unit tests covering validation, PNL, callbacks, reports, and event system
|
|
25
26
|
|
|
26
27
|
## Installation
|
|
@@ -252,6 +253,75 @@ for await (const result of Live.run("BTCUSDT", {
|
|
|
252
253
|
}
|
|
253
254
|
```
|
|
254
255
|
|
|
256
|
+
### 7. Schema Reflection API (Optional)
|
|
257
|
+
|
|
258
|
+
Retrieve registered schemas at runtime for debugging, documentation, or building dynamic UIs:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import {
|
|
262
|
+
addExchange,
|
|
263
|
+
addStrategy,
|
|
264
|
+
addFrame,
|
|
265
|
+
listExchanges,
|
|
266
|
+
listStrategies,
|
|
267
|
+
listFrames
|
|
268
|
+
} from "backtest-kit";
|
|
269
|
+
|
|
270
|
+
// Register schemas with notes
|
|
271
|
+
addExchange({
|
|
272
|
+
exchangeName: "binance",
|
|
273
|
+
note: "Binance cryptocurrency exchange with database backend",
|
|
274
|
+
getCandles: async (symbol, interval, since, limit) => [...],
|
|
275
|
+
formatPrice: async (symbol, price) => price.toFixed(2),
|
|
276
|
+
formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
addStrategy({
|
|
280
|
+
strategyName: "sma-crossover",
|
|
281
|
+
note: "Simple moving average crossover strategy (50/200)",
|
|
282
|
+
interval: "5m",
|
|
283
|
+
getSignal: async (symbol) => ({...}),
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
addFrame({
|
|
287
|
+
frameName: "january-2024",
|
|
288
|
+
note: "Full month backtest for January 2024",
|
|
289
|
+
interval: "1m",
|
|
290
|
+
startDate: new Date("2024-01-01"),
|
|
291
|
+
endDate: new Date("2024-02-01"),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// List all registered schemas
|
|
295
|
+
const exchanges = await listExchanges();
|
|
296
|
+
console.log("Available exchanges:", exchanges.map(e => ({
|
|
297
|
+
name: e.exchangeName,
|
|
298
|
+
note: e.note
|
|
299
|
+
})));
|
|
300
|
+
// Output: [{ name: "binance", note: "Binance cryptocurrency exchange..." }]
|
|
301
|
+
|
|
302
|
+
const strategies = await listStrategies();
|
|
303
|
+
console.log("Available strategies:", strategies.map(s => ({
|
|
304
|
+
name: s.strategyName,
|
|
305
|
+
note: s.note,
|
|
306
|
+
interval: s.interval
|
|
307
|
+
})));
|
|
308
|
+
// Output: [{ name: "sma-crossover", note: "Simple moving average...", interval: "5m" }]
|
|
309
|
+
|
|
310
|
+
const frames = await listFrames();
|
|
311
|
+
console.log("Available frames:", frames.map(f => ({
|
|
312
|
+
name: f.frameName,
|
|
313
|
+
note: f.note,
|
|
314
|
+
period: `${f.startDate.toISOString()} - ${f.endDate.toISOString()}`
|
|
315
|
+
})));
|
|
316
|
+
// Output: [{ name: "january-2024", note: "Full month backtest...", period: "2024-01-01..." }]
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Use cases:**
|
|
320
|
+
- Generate documentation automatically from registered schemas
|
|
321
|
+
- Build admin dashboards showing available strategies and exchanges
|
|
322
|
+
- Create CLI tools with auto-completion based on registered schemas
|
|
323
|
+
- Validate configuration files against registered schemas
|
|
324
|
+
|
|
255
325
|
## Architecture Overview
|
|
256
326
|
|
|
257
327
|
The framework follows **clean architecture** with:
|
|
@@ -794,41 +864,6 @@ pnl% = (priceOpenWithCosts - priceCloseWithCosts) / priceOpenWithCosts * 100
|
|
|
794
864
|
6. **Live Trading Ready** - Full implementation with real-time progression
|
|
795
865
|
7. **Error Recovery** - Stateless process with disk-based state
|
|
796
866
|
|
|
797
|
-
## File Structure
|
|
798
|
-
|
|
799
|
-
```
|
|
800
|
-
src/
|
|
801
|
-
โโโ client/ # Pure business logic (no DI)
|
|
802
|
-
โ โโโ ClientStrategy.ts # Signal lifecycle + validation + persistence
|
|
803
|
-
โ โโโ ClientExchange.ts # VWAP calculation
|
|
804
|
-
โ โโโ ClientFrame.ts # Timeframe generation
|
|
805
|
-
โโโ classes/
|
|
806
|
-
โ โโโ Persist.ts # Atomic file persistence
|
|
807
|
-
โโโ function/ # High-level API
|
|
808
|
-
โ โโโ add.ts # addStrategy, addExchange, addFrame
|
|
809
|
-
โ โโโ exchange.ts # getCandles, getAveragePrice, getDate, getMode
|
|
810
|
-
โ โโโ run.ts # DEPRECATED - use logic services instead
|
|
811
|
-
โโโ interfaces/ # TypeScript interfaces
|
|
812
|
-
โ โโโ Strategy.interface.ts
|
|
813
|
-
โ โโโ Exchange.interface.ts
|
|
814
|
-
โ โโโ Frame.interface.ts
|
|
815
|
-
โโโ lib/
|
|
816
|
-
โ โโโ core/ # DI container
|
|
817
|
-
โ โโโ services/
|
|
818
|
-
โ โ โโโ base/ # LoggerService
|
|
819
|
-
โ โ โโโ context/ # ExecutionContext, MethodContext
|
|
820
|
-
โ โ โโโ connection/ # Client instance creators
|
|
821
|
-
โ โ โโโ global/ # Context wrappers
|
|
822
|
-
โ โ โโโ schema/ # Registry services
|
|
823
|
-
โ โ โโโ logic/
|
|
824
|
-
โ โ โโโ private/ # Async generator orchestration
|
|
825
|
-
โ โ โโโ BacktestLogicPrivateService.ts
|
|
826
|
-
โ โ โโโ LiveLogicPrivateService.ts
|
|
827
|
-
โ โโโ index.ts # Public API
|
|
828
|
-
โโโ helpers/
|
|
829
|
-
โโโ toProfitLossDto.ts # PNL calculation
|
|
830
|
-
```
|
|
831
|
-
|
|
832
867
|
## Advanced Examples
|
|
833
868
|
|
|
834
869
|
### Multi-Symbol Live Trading
|
|
@@ -856,6 +891,24 @@ await Promise.all(
|
|
|
856
891
|
);
|
|
857
892
|
```
|
|
858
893
|
|
|
894
|
+
### Backtest Progress Listener
|
|
895
|
+
|
|
896
|
+
```typescript
|
|
897
|
+
import { listenProgress, Backtest } from "backtest-kit";
|
|
898
|
+
|
|
899
|
+
listenProgress((event) => {
|
|
900
|
+
console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
|
|
901
|
+
console.log(`${event.processedFrames} / ${event.totalFrames} frames`);
|
|
902
|
+
console.log(`Strategy: ${event.strategyName}, Symbol: ${event.symbol}`);
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
Backtest.background("BTCUSDT", {
|
|
906
|
+
strategyName: "my-strategy",
|
|
907
|
+
exchangeName: "binance",
|
|
908
|
+
frameName: "1d-backtest"
|
|
909
|
+
});
|
|
910
|
+
```
|
|
911
|
+
|
|
859
912
|
### Early Termination
|
|
860
913
|
|
|
861
914
|
**Using async generator with break:**
|
package/build/index.cjs
CHANGED
|
@@ -1129,6 +1129,11 @@ const errorEmitter = new functoolsKit.Subject();
|
|
|
1129
1129
|
* Emits when background tasks complete (Live.background, Backtest.background).
|
|
1130
1130
|
*/
|
|
1131
1131
|
const doneEmitter = new functoolsKit.Subject();
|
|
1132
|
+
/**
|
|
1133
|
+
* Progress emitter for backtest execution progress.
|
|
1134
|
+
* Emits progress updates during backtest execution.
|
|
1135
|
+
*/
|
|
1136
|
+
const progressEmitter = new functoolsKit.Subject();
|
|
1132
1137
|
|
|
1133
1138
|
const INTERVAL_MINUTES$1 = {
|
|
1134
1139
|
"1m": 1,
|
|
@@ -2402,6 +2407,7 @@ class BacktestLogicPrivateService {
|
|
|
2402
2407
|
this.strategyGlobalService = inject(TYPES.strategyGlobalService);
|
|
2403
2408
|
this.exchangeGlobalService = inject(TYPES.exchangeGlobalService);
|
|
2404
2409
|
this.frameGlobalService = inject(TYPES.frameGlobalService);
|
|
2410
|
+
this.methodContextService = inject(TYPES.methodContextService);
|
|
2405
2411
|
}
|
|
2406
2412
|
/**
|
|
2407
2413
|
* Runs backtest for a symbol, streaming closed signals as async generator.
|
|
@@ -2422,9 +2428,21 @@ class BacktestLogicPrivateService {
|
|
|
2422
2428
|
symbol,
|
|
2423
2429
|
});
|
|
2424
2430
|
const timeframes = await this.frameGlobalService.getTimeframe(symbol);
|
|
2431
|
+
const totalFrames = timeframes.length;
|
|
2425
2432
|
let i = 0;
|
|
2426
2433
|
while (i < timeframes.length) {
|
|
2427
2434
|
const when = timeframes[i];
|
|
2435
|
+
// Emit progress event if context is available
|
|
2436
|
+
{
|
|
2437
|
+
await progressEmitter.next({
|
|
2438
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
2439
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
2440
|
+
symbol,
|
|
2441
|
+
totalFrames,
|
|
2442
|
+
processedFrames: i,
|
|
2443
|
+
progress: totalFrames > 0 ? i / totalFrames : 0,
|
|
2444
|
+
});
|
|
2445
|
+
}
|
|
2428
2446
|
const result = await this.strategyGlobalService.tick(symbol, when, true);
|
|
2429
2447
|
// ะัะปะธ ัะธะณะฝะฐะป ะพัะบััั, ะฒัะทัะฒะฐะตะผ backtest
|
|
2430
2448
|
if (result.action === "opened") {
|
|
@@ -2461,6 +2479,17 @@ class BacktestLogicPrivateService {
|
|
|
2461
2479
|
}
|
|
2462
2480
|
i++;
|
|
2463
2481
|
}
|
|
2482
|
+
// Emit final progress event (100%)
|
|
2483
|
+
{
|
|
2484
|
+
await progressEmitter.next({
|
|
2485
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
2486
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
2487
|
+
symbol,
|
|
2488
|
+
totalFrames,
|
|
2489
|
+
processedFrames: totalFrames,
|
|
2490
|
+
progress: 1.0,
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2464
2493
|
}
|
|
2465
2494
|
}
|
|
2466
2495
|
|
|
@@ -3479,6 +3508,15 @@ class ExchangeValidationService {
|
|
|
3479
3508
|
}
|
|
3480
3509
|
return true;
|
|
3481
3510
|
});
|
|
3511
|
+
/**
|
|
3512
|
+
* Returns a list of all registered exchange schemas
|
|
3513
|
+
* @public
|
|
3514
|
+
* @returns Array of exchange schemas with their configurations
|
|
3515
|
+
*/
|
|
3516
|
+
this.list = async () => {
|
|
3517
|
+
this.loggerService.log("exchangeValidationService list");
|
|
3518
|
+
return Array.from(this._exchangeMap.values());
|
|
3519
|
+
};
|
|
3482
3520
|
}
|
|
3483
3521
|
}
|
|
3484
3522
|
|
|
@@ -3531,6 +3569,15 @@ class StrategyValidationService {
|
|
|
3531
3569
|
}
|
|
3532
3570
|
return true;
|
|
3533
3571
|
});
|
|
3572
|
+
/**
|
|
3573
|
+
* Returns a list of all registered strategy schemas
|
|
3574
|
+
* @public
|
|
3575
|
+
* @returns Array of strategy schemas with their configurations
|
|
3576
|
+
*/
|
|
3577
|
+
this.list = async () => {
|
|
3578
|
+
this.loggerService.log("strategyValidationService list");
|
|
3579
|
+
return Array.from(this._strategyMap.values());
|
|
3580
|
+
};
|
|
3534
3581
|
}
|
|
3535
3582
|
}
|
|
3536
3583
|
|
|
@@ -3583,6 +3630,15 @@ class FrameValidationService {
|
|
|
3583
3630
|
}
|
|
3584
3631
|
return true;
|
|
3585
3632
|
});
|
|
3633
|
+
/**
|
|
3634
|
+
* Returns a list of all registered frame schemas
|
|
3635
|
+
* @public
|
|
3636
|
+
* @returns Array of frame schemas with their configurations
|
|
3637
|
+
*/
|
|
3638
|
+
this.list = async () => {
|
|
3639
|
+
this.loggerService.log("frameValidationService list");
|
|
3640
|
+
return Array.from(this._frameMap.values());
|
|
3641
|
+
};
|
|
3586
3642
|
}
|
|
3587
3643
|
}
|
|
3588
3644
|
|
|
@@ -3828,6 +3884,102 @@ function addFrame(frameSchema) {
|
|
|
3828
3884
|
backtest$1.frameSchemaService.register(frameSchema.frameName, frameSchema);
|
|
3829
3885
|
}
|
|
3830
3886
|
|
|
3887
|
+
const LIST_EXCHANGES_METHOD_NAME = "list.listExchanges";
|
|
3888
|
+
const LIST_STRATEGIES_METHOD_NAME = "list.listStrategies";
|
|
3889
|
+
const LIST_FRAMES_METHOD_NAME = "list.listFrames";
|
|
3890
|
+
/**
|
|
3891
|
+
* Returns a list of all registered exchange schemas.
|
|
3892
|
+
*
|
|
3893
|
+
* Retrieves all exchanges that have been registered via addExchange().
|
|
3894
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3895
|
+
*
|
|
3896
|
+
* @returns Array of exchange schemas with their configurations
|
|
3897
|
+
*
|
|
3898
|
+
* @example
|
|
3899
|
+
* ```typescript
|
|
3900
|
+
* import { listExchanges, addExchange } from "backtest-kit";
|
|
3901
|
+
*
|
|
3902
|
+
* addExchange({
|
|
3903
|
+
* exchangeName: "binance",
|
|
3904
|
+
* note: "Binance cryptocurrency exchange",
|
|
3905
|
+
* getCandles: async (symbol, interval, since, limit) => [...],
|
|
3906
|
+
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
3907
|
+
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
3908
|
+
* });
|
|
3909
|
+
*
|
|
3910
|
+
* const exchanges = listExchanges();
|
|
3911
|
+
* console.log(exchanges);
|
|
3912
|
+
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
3913
|
+
* ```
|
|
3914
|
+
*/
|
|
3915
|
+
async function listExchanges() {
|
|
3916
|
+
backtest$1.loggerService.log(LIST_EXCHANGES_METHOD_NAME);
|
|
3917
|
+
return await backtest$1.exchangeValidationService.list();
|
|
3918
|
+
}
|
|
3919
|
+
/**
|
|
3920
|
+
* Returns a list of all registered strategy schemas.
|
|
3921
|
+
*
|
|
3922
|
+
* Retrieves all strategies that have been registered via addStrategy().
|
|
3923
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3924
|
+
*
|
|
3925
|
+
* @returns Array of strategy schemas with their configurations
|
|
3926
|
+
*
|
|
3927
|
+
* @example
|
|
3928
|
+
* ```typescript
|
|
3929
|
+
* import { listStrategies, addStrategy } from "backtest-kit";
|
|
3930
|
+
*
|
|
3931
|
+
* addStrategy({
|
|
3932
|
+
* strategyName: "my-strategy",
|
|
3933
|
+
* note: "Simple moving average crossover strategy",
|
|
3934
|
+
* interval: "5m",
|
|
3935
|
+
* getSignal: async (symbol) => ({
|
|
3936
|
+
* position: "long",
|
|
3937
|
+
* priceOpen: 50000,
|
|
3938
|
+
* priceTakeProfit: 51000,
|
|
3939
|
+
* priceStopLoss: 49000,
|
|
3940
|
+
* minuteEstimatedTime: 60,
|
|
3941
|
+
* }),
|
|
3942
|
+
* });
|
|
3943
|
+
*
|
|
3944
|
+
* const strategies = listStrategies();
|
|
3945
|
+
* console.log(strategies);
|
|
3946
|
+
* // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
|
|
3947
|
+
* ```
|
|
3948
|
+
*/
|
|
3949
|
+
async function listStrategies() {
|
|
3950
|
+
backtest$1.loggerService.log(LIST_STRATEGIES_METHOD_NAME);
|
|
3951
|
+
return await backtest$1.strategyValidationService.list();
|
|
3952
|
+
}
|
|
3953
|
+
/**
|
|
3954
|
+
* Returns a list of all registered frame schemas.
|
|
3955
|
+
*
|
|
3956
|
+
* Retrieves all frames that have been registered via addFrame().
|
|
3957
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3958
|
+
*
|
|
3959
|
+
* @returns Array of frame schemas with their configurations
|
|
3960
|
+
*
|
|
3961
|
+
* @example
|
|
3962
|
+
* ```typescript
|
|
3963
|
+
* import { listFrames, addFrame } from "backtest-kit";
|
|
3964
|
+
*
|
|
3965
|
+
* addFrame({
|
|
3966
|
+
* frameName: "1d-backtest",
|
|
3967
|
+
* note: "One day backtest period for testing",
|
|
3968
|
+
* interval: "1m",
|
|
3969
|
+
* startDate: new Date("2024-01-01T00:00:00Z"),
|
|
3970
|
+
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
3971
|
+
* });
|
|
3972
|
+
*
|
|
3973
|
+
* const frames = listFrames();
|
|
3974
|
+
* console.log(frames);
|
|
3975
|
+
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
3976
|
+
* ```
|
|
3977
|
+
*/
|
|
3978
|
+
async function listFrames() {
|
|
3979
|
+
backtest$1.loggerService.log(LIST_FRAMES_METHOD_NAME);
|
|
3980
|
+
return await backtest$1.frameValidationService.list();
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3831
3983
|
const LISTEN_SIGNAL_METHOD_NAME = "event.listenSignal";
|
|
3832
3984
|
const LISTEN_SIGNAL_ONCE_METHOD_NAME = "event.listenSignalOnce";
|
|
3833
3985
|
const LISTEN_SIGNAL_LIVE_METHOD_NAME = "event.listenSignalLive";
|
|
@@ -3837,6 +3989,7 @@ const LISTEN_SIGNAL_BACKTEST_ONCE_METHOD_NAME = "event.listenSignalBacktestOnce"
|
|
|
3837
3989
|
const LISTEN_ERROR_METHOD_NAME = "event.listenError";
|
|
3838
3990
|
const LISTEN_DONE_METHOD_NAME = "event.listenDone";
|
|
3839
3991
|
const LISTEN_DONE_ONCE_METHOD_NAME = "event.listenDoneOnce";
|
|
3992
|
+
const LISTEN_PROGRESS_METHOD_NAME = "event.listenProgress";
|
|
3840
3993
|
/**
|
|
3841
3994
|
* Subscribes to all signal events with queued async processing.
|
|
3842
3995
|
*
|
|
@@ -4092,6 +4245,40 @@ function listenDoneOnce(filterFn, fn) {
|
|
|
4092
4245
|
backtest$1.loggerService.log(LISTEN_DONE_ONCE_METHOD_NAME);
|
|
4093
4246
|
return doneEmitter.filter(filterFn).once(fn);
|
|
4094
4247
|
}
|
|
4248
|
+
/**
|
|
4249
|
+
* Subscribes to backtest progress events with queued async processing.
|
|
4250
|
+
*
|
|
4251
|
+
* Emits during Backtest.background() execution to track progress.
|
|
4252
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
4253
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
4254
|
+
*
|
|
4255
|
+
* @param fn - Callback function to handle progress events
|
|
4256
|
+
* @returns Unsubscribe function to stop listening to events
|
|
4257
|
+
*
|
|
4258
|
+
* @example
|
|
4259
|
+
* ```typescript
|
|
4260
|
+
* import { listenProgress, Backtest } from "backtest-kit";
|
|
4261
|
+
*
|
|
4262
|
+
* const unsubscribe = listenProgress((event) => {
|
|
4263
|
+
* console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
|
|
4264
|
+
* console.log(`${event.processedFrames} / ${event.totalFrames} frames`);
|
|
4265
|
+
* console.log(`Strategy: ${event.strategyName}, Symbol: ${event.symbol}`);
|
|
4266
|
+
* });
|
|
4267
|
+
*
|
|
4268
|
+
* Backtest.background("BTCUSDT", {
|
|
4269
|
+
* strategyName: "my-strategy",
|
|
4270
|
+
* exchangeName: "binance",
|
|
4271
|
+
* frameName: "1d-backtest"
|
|
4272
|
+
* });
|
|
4273
|
+
*
|
|
4274
|
+
* // Later: stop listening
|
|
4275
|
+
* unsubscribe();
|
|
4276
|
+
* ```
|
|
4277
|
+
*/
|
|
4278
|
+
function listenProgress(fn) {
|
|
4279
|
+
backtest$1.loggerService.log(LISTEN_PROGRESS_METHOD_NAME);
|
|
4280
|
+
return progressEmitter.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
4281
|
+
}
|
|
4095
4282
|
|
|
4096
4283
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
4097
4284
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
@@ -4556,9 +4743,13 @@ exports.getCandles = getCandles;
|
|
|
4556
4743
|
exports.getDate = getDate;
|
|
4557
4744
|
exports.getMode = getMode;
|
|
4558
4745
|
exports.lib = backtest;
|
|
4746
|
+
exports.listExchanges = listExchanges;
|
|
4747
|
+
exports.listFrames = listFrames;
|
|
4748
|
+
exports.listStrategies = listStrategies;
|
|
4559
4749
|
exports.listenDone = listenDone;
|
|
4560
4750
|
exports.listenDoneOnce = listenDoneOnce;
|
|
4561
4751
|
exports.listenError = listenError;
|
|
4752
|
+
exports.listenProgress = listenProgress;
|
|
4562
4753
|
exports.listenSignal = listenSignal;
|
|
4563
4754
|
exports.listenSignalBacktest = listenSignalBacktest;
|
|
4564
4755
|
exports.listenSignalBacktestOnce = listenSignalBacktestOnce;
|
package/build/index.mjs
CHANGED
|
@@ -1127,6 +1127,11 @@ const errorEmitter = new Subject();
|
|
|
1127
1127
|
* Emits when background tasks complete (Live.background, Backtest.background).
|
|
1128
1128
|
*/
|
|
1129
1129
|
const doneEmitter = new Subject();
|
|
1130
|
+
/**
|
|
1131
|
+
* Progress emitter for backtest execution progress.
|
|
1132
|
+
* Emits progress updates during backtest execution.
|
|
1133
|
+
*/
|
|
1134
|
+
const progressEmitter = new Subject();
|
|
1130
1135
|
|
|
1131
1136
|
const INTERVAL_MINUTES$1 = {
|
|
1132
1137
|
"1m": 1,
|
|
@@ -2400,6 +2405,7 @@ class BacktestLogicPrivateService {
|
|
|
2400
2405
|
this.strategyGlobalService = inject(TYPES.strategyGlobalService);
|
|
2401
2406
|
this.exchangeGlobalService = inject(TYPES.exchangeGlobalService);
|
|
2402
2407
|
this.frameGlobalService = inject(TYPES.frameGlobalService);
|
|
2408
|
+
this.methodContextService = inject(TYPES.methodContextService);
|
|
2403
2409
|
}
|
|
2404
2410
|
/**
|
|
2405
2411
|
* Runs backtest for a symbol, streaming closed signals as async generator.
|
|
@@ -2420,9 +2426,21 @@ class BacktestLogicPrivateService {
|
|
|
2420
2426
|
symbol,
|
|
2421
2427
|
});
|
|
2422
2428
|
const timeframes = await this.frameGlobalService.getTimeframe(symbol);
|
|
2429
|
+
const totalFrames = timeframes.length;
|
|
2423
2430
|
let i = 0;
|
|
2424
2431
|
while (i < timeframes.length) {
|
|
2425
2432
|
const when = timeframes[i];
|
|
2433
|
+
// Emit progress event if context is available
|
|
2434
|
+
{
|
|
2435
|
+
await progressEmitter.next({
|
|
2436
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
2437
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
2438
|
+
symbol,
|
|
2439
|
+
totalFrames,
|
|
2440
|
+
processedFrames: i,
|
|
2441
|
+
progress: totalFrames > 0 ? i / totalFrames : 0,
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2426
2444
|
const result = await this.strategyGlobalService.tick(symbol, when, true);
|
|
2427
2445
|
// ะัะปะธ ัะธะณะฝะฐะป ะพัะบััั, ะฒัะทัะฒะฐะตะผ backtest
|
|
2428
2446
|
if (result.action === "opened") {
|
|
@@ -2459,6 +2477,17 @@ class BacktestLogicPrivateService {
|
|
|
2459
2477
|
}
|
|
2460
2478
|
i++;
|
|
2461
2479
|
}
|
|
2480
|
+
// Emit final progress event (100%)
|
|
2481
|
+
{
|
|
2482
|
+
await progressEmitter.next({
|
|
2483
|
+
exchangeName: this.methodContextService.context.exchangeName,
|
|
2484
|
+
strategyName: this.methodContextService.context.strategyName,
|
|
2485
|
+
symbol,
|
|
2486
|
+
totalFrames,
|
|
2487
|
+
processedFrames: totalFrames,
|
|
2488
|
+
progress: 1.0,
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2462
2491
|
}
|
|
2463
2492
|
}
|
|
2464
2493
|
|
|
@@ -3477,6 +3506,15 @@ class ExchangeValidationService {
|
|
|
3477
3506
|
}
|
|
3478
3507
|
return true;
|
|
3479
3508
|
});
|
|
3509
|
+
/**
|
|
3510
|
+
* Returns a list of all registered exchange schemas
|
|
3511
|
+
* @public
|
|
3512
|
+
* @returns Array of exchange schemas with their configurations
|
|
3513
|
+
*/
|
|
3514
|
+
this.list = async () => {
|
|
3515
|
+
this.loggerService.log("exchangeValidationService list");
|
|
3516
|
+
return Array.from(this._exchangeMap.values());
|
|
3517
|
+
};
|
|
3480
3518
|
}
|
|
3481
3519
|
}
|
|
3482
3520
|
|
|
@@ -3529,6 +3567,15 @@ class StrategyValidationService {
|
|
|
3529
3567
|
}
|
|
3530
3568
|
return true;
|
|
3531
3569
|
});
|
|
3570
|
+
/**
|
|
3571
|
+
* Returns a list of all registered strategy schemas
|
|
3572
|
+
* @public
|
|
3573
|
+
* @returns Array of strategy schemas with their configurations
|
|
3574
|
+
*/
|
|
3575
|
+
this.list = async () => {
|
|
3576
|
+
this.loggerService.log("strategyValidationService list");
|
|
3577
|
+
return Array.from(this._strategyMap.values());
|
|
3578
|
+
};
|
|
3532
3579
|
}
|
|
3533
3580
|
}
|
|
3534
3581
|
|
|
@@ -3581,6 +3628,15 @@ class FrameValidationService {
|
|
|
3581
3628
|
}
|
|
3582
3629
|
return true;
|
|
3583
3630
|
});
|
|
3631
|
+
/**
|
|
3632
|
+
* Returns a list of all registered frame schemas
|
|
3633
|
+
* @public
|
|
3634
|
+
* @returns Array of frame schemas with their configurations
|
|
3635
|
+
*/
|
|
3636
|
+
this.list = async () => {
|
|
3637
|
+
this.loggerService.log("frameValidationService list");
|
|
3638
|
+
return Array.from(this._frameMap.values());
|
|
3639
|
+
};
|
|
3584
3640
|
}
|
|
3585
3641
|
}
|
|
3586
3642
|
|
|
@@ -3826,6 +3882,102 @@ function addFrame(frameSchema) {
|
|
|
3826
3882
|
backtest$1.frameSchemaService.register(frameSchema.frameName, frameSchema);
|
|
3827
3883
|
}
|
|
3828
3884
|
|
|
3885
|
+
const LIST_EXCHANGES_METHOD_NAME = "list.listExchanges";
|
|
3886
|
+
const LIST_STRATEGIES_METHOD_NAME = "list.listStrategies";
|
|
3887
|
+
const LIST_FRAMES_METHOD_NAME = "list.listFrames";
|
|
3888
|
+
/**
|
|
3889
|
+
* Returns a list of all registered exchange schemas.
|
|
3890
|
+
*
|
|
3891
|
+
* Retrieves all exchanges that have been registered via addExchange().
|
|
3892
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3893
|
+
*
|
|
3894
|
+
* @returns Array of exchange schemas with their configurations
|
|
3895
|
+
*
|
|
3896
|
+
* @example
|
|
3897
|
+
* ```typescript
|
|
3898
|
+
* import { listExchanges, addExchange } from "backtest-kit";
|
|
3899
|
+
*
|
|
3900
|
+
* addExchange({
|
|
3901
|
+
* exchangeName: "binance",
|
|
3902
|
+
* note: "Binance cryptocurrency exchange",
|
|
3903
|
+
* getCandles: async (symbol, interval, since, limit) => [...],
|
|
3904
|
+
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
3905
|
+
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
3906
|
+
* });
|
|
3907
|
+
*
|
|
3908
|
+
* const exchanges = listExchanges();
|
|
3909
|
+
* console.log(exchanges);
|
|
3910
|
+
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
3911
|
+
* ```
|
|
3912
|
+
*/
|
|
3913
|
+
async function listExchanges() {
|
|
3914
|
+
backtest$1.loggerService.log(LIST_EXCHANGES_METHOD_NAME);
|
|
3915
|
+
return await backtest$1.exchangeValidationService.list();
|
|
3916
|
+
}
|
|
3917
|
+
/**
|
|
3918
|
+
* Returns a list of all registered strategy schemas.
|
|
3919
|
+
*
|
|
3920
|
+
* Retrieves all strategies that have been registered via addStrategy().
|
|
3921
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3922
|
+
*
|
|
3923
|
+
* @returns Array of strategy schemas with their configurations
|
|
3924
|
+
*
|
|
3925
|
+
* @example
|
|
3926
|
+
* ```typescript
|
|
3927
|
+
* import { listStrategies, addStrategy } from "backtest-kit";
|
|
3928
|
+
*
|
|
3929
|
+
* addStrategy({
|
|
3930
|
+
* strategyName: "my-strategy",
|
|
3931
|
+
* note: "Simple moving average crossover strategy",
|
|
3932
|
+
* interval: "5m",
|
|
3933
|
+
* getSignal: async (symbol) => ({
|
|
3934
|
+
* position: "long",
|
|
3935
|
+
* priceOpen: 50000,
|
|
3936
|
+
* priceTakeProfit: 51000,
|
|
3937
|
+
* priceStopLoss: 49000,
|
|
3938
|
+
* minuteEstimatedTime: 60,
|
|
3939
|
+
* }),
|
|
3940
|
+
* });
|
|
3941
|
+
*
|
|
3942
|
+
* const strategies = listStrategies();
|
|
3943
|
+
* console.log(strategies);
|
|
3944
|
+
* // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
|
|
3945
|
+
* ```
|
|
3946
|
+
*/
|
|
3947
|
+
async function listStrategies() {
|
|
3948
|
+
backtest$1.loggerService.log(LIST_STRATEGIES_METHOD_NAME);
|
|
3949
|
+
return await backtest$1.strategyValidationService.list();
|
|
3950
|
+
}
|
|
3951
|
+
/**
|
|
3952
|
+
* Returns a list of all registered frame schemas.
|
|
3953
|
+
*
|
|
3954
|
+
* Retrieves all frames that have been registered via addFrame().
|
|
3955
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
3956
|
+
*
|
|
3957
|
+
* @returns Array of frame schemas with their configurations
|
|
3958
|
+
*
|
|
3959
|
+
* @example
|
|
3960
|
+
* ```typescript
|
|
3961
|
+
* import { listFrames, addFrame } from "backtest-kit";
|
|
3962
|
+
*
|
|
3963
|
+
* addFrame({
|
|
3964
|
+
* frameName: "1d-backtest",
|
|
3965
|
+
* note: "One day backtest period for testing",
|
|
3966
|
+
* interval: "1m",
|
|
3967
|
+
* startDate: new Date("2024-01-01T00:00:00Z"),
|
|
3968
|
+
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
3969
|
+
* });
|
|
3970
|
+
*
|
|
3971
|
+
* const frames = listFrames();
|
|
3972
|
+
* console.log(frames);
|
|
3973
|
+
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
3974
|
+
* ```
|
|
3975
|
+
*/
|
|
3976
|
+
async function listFrames() {
|
|
3977
|
+
backtest$1.loggerService.log(LIST_FRAMES_METHOD_NAME);
|
|
3978
|
+
return await backtest$1.frameValidationService.list();
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3829
3981
|
const LISTEN_SIGNAL_METHOD_NAME = "event.listenSignal";
|
|
3830
3982
|
const LISTEN_SIGNAL_ONCE_METHOD_NAME = "event.listenSignalOnce";
|
|
3831
3983
|
const LISTEN_SIGNAL_LIVE_METHOD_NAME = "event.listenSignalLive";
|
|
@@ -3835,6 +3987,7 @@ const LISTEN_SIGNAL_BACKTEST_ONCE_METHOD_NAME = "event.listenSignalBacktestOnce"
|
|
|
3835
3987
|
const LISTEN_ERROR_METHOD_NAME = "event.listenError";
|
|
3836
3988
|
const LISTEN_DONE_METHOD_NAME = "event.listenDone";
|
|
3837
3989
|
const LISTEN_DONE_ONCE_METHOD_NAME = "event.listenDoneOnce";
|
|
3990
|
+
const LISTEN_PROGRESS_METHOD_NAME = "event.listenProgress";
|
|
3838
3991
|
/**
|
|
3839
3992
|
* Subscribes to all signal events with queued async processing.
|
|
3840
3993
|
*
|
|
@@ -4090,6 +4243,40 @@ function listenDoneOnce(filterFn, fn) {
|
|
|
4090
4243
|
backtest$1.loggerService.log(LISTEN_DONE_ONCE_METHOD_NAME);
|
|
4091
4244
|
return doneEmitter.filter(filterFn).once(fn);
|
|
4092
4245
|
}
|
|
4246
|
+
/**
|
|
4247
|
+
* Subscribes to backtest progress events with queued async processing.
|
|
4248
|
+
*
|
|
4249
|
+
* Emits during Backtest.background() execution to track progress.
|
|
4250
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
4251
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
4252
|
+
*
|
|
4253
|
+
* @param fn - Callback function to handle progress events
|
|
4254
|
+
* @returns Unsubscribe function to stop listening to events
|
|
4255
|
+
*
|
|
4256
|
+
* @example
|
|
4257
|
+
* ```typescript
|
|
4258
|
+
* import { listenProgress, Backtest } from "backtest-kit";
|
|
4259
|
+
*
|
|
4260
|
+
* const unsubscribe = listenProgress((event) => {
|
|
4261
|
+
* console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
|
|
4262
|
+
* console.log(`${event.processedFrames} / ${event.totalFrames} frames`);
|
|
4263
|
+
* console.log(`Strategy: ${event.strategyName}, Symbol: ${event.symbol}`);
|
|
4264
|
+
* });
|
|
4265
|
+
*
|
|
4266
|
+
* Backtest.background("BTCUSDT", {
|
|
4267
|
+
* strategyName: "my-strategy",
|
|
4268
|
+
* exchangeName: "binance",
|
|
4269
|
+
* frameName: "1d-backtest"
|
|
4270
|
+
* });
|
|
4271
|
+
*
|
|
4272
|
+
* // Later: stop listening
|
|
4273
|
+
* unsubscribe();
|
|
4274
|
+
* ```
|
|
4275
|
+
*/
|
|
4276
|
+
function listenProgress(fn) {
|
|
4277
|
+
backtest$1.loggerService.log(LISTEN_PROGRESS_METHOD_NAME);
|
|
4278
|
+
return progressEmitter.subscribe(queued(async (event) => fn(event)));
|
|
4279
|
+
}
|
|
4093
4280
|
|
|
4094
4281
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
4095
4282
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
@@ -4538,4 +4725,4 @@ class LiveUtils {
|
|
|
4538
4725
|
*/
|
|
4539
4726
|
const Live = new LiveUtils();
|
|
4540
4727
|
|
|
4541
|
-
export { Backtest, ExecutionContextService, Live, MethodContextService, PersistBase, PersistSignalAdaper, addExchange, addFrame, addStrategy, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listenDone, listenDoneOnce, listenError, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, setLogger };
|
|
4728
|
+
export { Backtest, ExecutionContextService, Live, MethodContextService, PersistBase, PersistSignalAdaper, addExchange, addFrame, addStrategy, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listStrategies, listenDone, listenDoneOnce, listenError, listenProgress, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, setLogger };
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -140,6 +140,8 @@ interface IExchangeCallbacks {
|
|
|
140
140
|
interface IExchangeSchema {
|
|
141
141
|
/** Unique exchange identifier for registration */
|
|
142
142
|
exchangeName: ExchangeName;
|
|
143
|
+
/** Optional developer note for documentation */
|
|
144
|
+
note?: string;
|
|
143
145
|
/**
|
|
144
146
|
* Fetch candles from data source (API or database).
|
|
145
147
|
*
|
|
@@ -278,6 +280,8 @@ interface IFrameCallbacks {
|
|
|
278
280
|
interface IFrameSchema {
|
|
279
281
|
/** Unique identifier for this frame */
|
|
280
282
|
frameName: FrameName;
|
|
283
|
+
/** Optional developer note for documentation */
|
|
284
|
+
note?: string;
|
|
281
285
|
/** Interval for timestamp generation */
|
|
282
286
|
interval: FrameInterval;
|
|
283
287
|
/** Start of backtest period (inclusive) */
|
|
@@ -413,6 +417,8 @@ interface IStrategyCallbacks {
|
|
|
413
417
|
interface IStrategySchema {
|
|
414
418
|
/** Unique strategy identifier for registration */
|
|
415
419
|
strategyName: StrategyName;
|
|
420
|
+
/** Optional developer note for documentation */
|
|
421
|
+
note?: string;
|
|
416
422
|
/** Minimum interval between getSignal calls (throttling) */
|
|
417
423
|
interval: SignalInterval;
|
|
418
424
|
/** Signal generation function (returns null if no signal, validated DTO if signal) */
|
|
@@ -666,6 +672,90 @@ declare function addExchange(exchangeSchema: IExchangeSchema): void;
|
|
|
666
672
|
*/
|
|
667
673
|
declare function addFrame(frameSchema: IFrameSchema): void;
|
|
668
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Returns a list of all registered exchange schemas.
|
|
677
|
+
*
|
|
678
|
+
* Retrieves all exchanges that have been registered via addExchange().
|
|
679
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
680
|
+
*
|
|
681
|
+
* @returns Array of exchange schemas with their configurations
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* import { listExchanges, addExchange } from "backtest-kit";
|
|
686
|
+
*
|
|
687
|
+
* addExchange({
|
|
688
|
+
* exchangeName: "binance",
|
|
689
|
+
* note: "Binance cryptocurrency exchange",
|
|
690
|
+
* getCandles: async (symbol, interval, since, limit) => [...],
|
|
691
|
+
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
692
|
+
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
693
|
+
* });
|
|
694
|
+
*
|
|
695
|
+
* const exchanges = listExchanges();
|
|
696
|
+
* console.log(exchanges);
|
|
697
|
+
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
698
|
+
* ```
|
|
699
|
+
*/
|
|
700
|
+
declare function listExchanges(): Promise<IExchangeSchema[]>;
|
|
701
|
+
/**
|
|
702
|
+
* Returns a list of all registered strategy schemas.
|
|
703
|
+
*
|
|
704
|
+
* Retrieves all strategies that have been registered via addStrategy().
|
|
705
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
706
|
+
*
|
|
707
|
+
* @returns Array of strategy schemas with their configurations
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* import { listStrategies, addStrategy } from "backtest-kit";
|
|
712
|
+
*
|
|
713
|
+
* addStrategy({
|
|
714
|
+
* strategyName: "my-strategy",
|
|
715
|
+
* note: "Simple moving average crossover strategy",
|
|
716
|
+
* interval: "5m",
|
|
717
|
+
* getSignal: async (symbol) => ({
|
|
718
|
+
* position: "long",
|
|
719
|
+
* priceOpen: 50000,
|
|
720
|
+
* priceTakeProfit: 51000,
|
|
721
|
+
* priceStopLoss: 49000,
|
|
722
|
+
* minuteEstimatedTime: 60,
|
|
723
|
+
* }),
|
|
724
|
+
* });
|
|
725
|
+
*
|
|
726
|
+
* const strategies = listStrategies();
|
|
727
|
+
* console.log(strategies);
|
|
728
|
+
* // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
|
|
729
|
+
* ```
|
|
730
|
+
*/
|
|
731
|
+
declare function listStrategies(): Promise<IStrategySchema[]>;
|
|
732
|
+
/**
|
|
733
|
+
* Returns a list of all registered frame schemas.
|
|
734
|
+
*
|
|
735
|
+
* Retrieves all frames that have been registered via addFrame().
|
|
736
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
737
|
+
*
|
|
738
|
+
* @returns Array of frame schemas with their configurations
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```typescript
|
|
742
|
+
* import { listFrames, addFrame } from "backtest-kit";
|
|
743
|
+
*
|
|
744
|
+
* addFrame({
|
|
745
|
+
* frameName: "1d-backtest",
|
|
746
|
+
* note: "One day backtest period for testing",
|
|
747
|
+
* interval: "1m",
|
|
748
|
+
* startDate: new Date("2024-01-01T00:00:00Z"),
|
|
749
|
+
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
750
|
+
* });
|
|
751
|
+
*
|
|
752
|
+
* const frames = listFrames();
|
|
753
|
+
* console.log(frames);
|
|
754
|
+
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
757
|
+
declare function listFrames(): Promise<IFrameSchema[]>;
|
|
758
|
+
|
|
669
759
|
/**
|
|
670
760
|
* Contract for background execution completion events.
|
|
671
761
|
*
|
|
@@ -696,6 +786,37 @@ interface DoneContract {
|
|
|
696
786
|
symbol: string;
|
|
697
787
|
}
|
|
698
788
|
|
|
789
|
+
/**
|
|
790
|
+
* Contract for backtest progress events.
|
|
791
|
+
*
|
|
792
|
+
* Emitted during Backtest.background() execution to track progress.
|
|
793
|
+
* Contains information about total frames, processed frames, and completion percentage.
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* ```typescript
|
|
797
|
+
* import { listenProgress } from "backtest-kit";
|
|
798
|
+
*
|
|
799
|
+
* listenProgress((event) => {
|
|
800
|
+
* console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
|
|
801
|
+
* console.log(`Processed: ${event.processedFrames} / ${event.totalFrames}`);
|
|
802
|
+
* });
|
|
803
|
+
* ```
|
|
804
|
+
*/
|
|
805
|
+
interface ProgressContract {
|
|
806
|
+
/** exchangeName - Name of the exchange used in execution */
|
|
807
|
+
exchangeName: string;
|
|
808
|
+
/** strategyName - Name of the strategy being executed */
|
|
809
|
+
strategyName: string;
|
|
810
|
+
/** symbol - Trading symbol (e.g., "BTCUSDT") */
|
|
811
|
+
symbol: string;
|
|
812
|
+
/** totalFrames - Total number of frames to process */
|
|
813
|
+
totalFrames: number;
|
|
814
|
+
/** processedFrames - Number of frames processed so far */
|
|
815
|
+
processedFrames: number;
|
|
816
|
+
/** progress - Completion percentage from 0.0 to 1.0 */
|
|
817
|
+
progress: number;
|
|
818
|
+
}
|
|
819
|
+
|
|
699
820
|
/**
|
|
700
821
|
* Subscribes to all signal events with queued async processing.
|
|
701
822
|
*
|
|
@@ -924,6 +1045,37 @@ declare function listenDone(fn: (event: DoneContract) => void): () => void;
|
|
|
924
1045
|
* ```
|
|
925
1046
|
*/
|
|
926
1047
|
declare function listenDoneOnce(filterFn: (event: DoneContract) => boolean, fn: (event: DoneContract) => void): () => void;
|
|
1048
|
+
/**
|
|
1049
|
+
* Subscribes to backtest progress events with queued async processing.
|
|
1050
|
+
*
|
|
1051
|
+
* Emits during Backtest.background() execution to track progress.
|
|
1052
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
1053
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
1054
|
+
*
|
|
1055
|
+
* @param fn - Callback function to handle progress events
|
|
1056
|
+
* @returns Unsubscribe function to stop listening to events
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* ```typescript
|
|
1060
|
+
* import { listenProgress, Backtest } from "backtest-kit";
|
|
1061
|
+
*
|
|
1062
|
+
* const unsubscribe = listenProgress((event) => {
|
|
1063
|
+
* console.log(`Progress: ${(event.progress * 100).toFixed(2)}%`);
|
|
1064
|
+
* console.log(`${event.processedFrames} / ${event.totalFrames} frames`);
|
|
1065
|
+
* console.log(`Strategy: ${event.strategyName}, Symbol: ${event.symbol}`);
|
|
1066
|
+
* });
|
|
1067
|
+
*
|
|
1068
|
+
* Backtest.background("BTCUSDT", {
|
|
1069
|
+
* strategyName: "my-strategy",
|
|
1070
|
+
* exchangeName: "binance",
|
|
1071
|
+
* frameName: "1d-backtest"
|
|
1072
|
+
* });
|
|
1073
|
+
*
|
|
1074
|
+
* // Later: stop listening
|
|
1075
|
+
* unsubscribe();
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
declare function listenProgress(fn: (event: ProgressContract) => void): () => void;
|
|
927
1079
|
|
|
928
1080
|
/**
|
|
929
1081
|
* Fetches historical candle data from the registered exchange.
|
|
@@ -2154,6 +2306,7 @@ declare class BacktestLogicPrivateService {
|
|
|
2154
2306
|
private readonly strategyGlobalService;
|
|
2155
2307
|
private readonly exchangeGlobalService;
|
|
2156
2308
|
private readonly frameGlobalService;
|
|
2309
|
+
private readonly methodContextService;
|
|
2157
2310
|
/**
|
|
2158
2311
|
* Runs backtest for a symbol, streaming closed signals as async generator.
|
|
2159
2312
|
*
|
|
@@ -2642,6 +2795,12 @@ declare class ExchangeValidationService {
|
|
|
2642
2795
|
* Memoized function to cache validation results
|
|
2643
2796
|
*/
|
|
2644
2797
|
validate: (exchangeName: ExchangeName, source: string) => void;
|
|
2798
|
+
/**
|
|
2799
|
+
* Returns a list of all registered exchange schemas
|
|
2800
|
+
* @public
|
|
2801
|
+
* @returns Array of exchange schemas with their configurations
|
|
2802
|
+
*/
|
|
2803
|
+
list: () => Promise<IExchangeSchema[]>;
|
|
2645
2804
|
}
|
|
2646
2805
|
|
|
2647
2806
|
/**
|
|
@@ -2673,6 +2832,12 @@ declare class StrategyValidationService {
|
|
|
2673
2832
|
* Memoized function to cache validation results
|
|
2674
2833
|
*/
|
|
2675
2834
|
validate: (strategyName: StrategyName, source: string) => void;
|
|
2835
|
+
/**
|
|
2836
|
+
* Returns a list of all registered strategy schemas
|
|
2837
|
+
* @public
|
|
2838
|
+
* @returns Array of strategy schemas with their configurations
|
|
2839
|
+
*/
|
|
2840
|
+
list: () => Promise<IStrategySchema[]>;
|
|
2676
2841
|
}
|
|
2677
2842
|
|
|
2678
2843
|
/**
|
|
@@ -2704,6 +2869,12 @@ declare class FrameValidationService {
|
|
|
2704
2869
|
* Memoized function to cache validation results
|
|
2705
2870
|
*/
|
|
2706
2871
|
validate: (frameName: FrameName, source: string) => void;
|
|
2872
|
+
/**
|
|
2873
|
+
* Returns a list of all registered frame schemas
|
|
2874
|
+
* @public
|
|
2875
|
+
* @returns Array of frame schemas with their configurations
|
|
2876
|
+
*/
|
|
2877
|
+
list: () => Promise<IFrameSchema[]>;
|
|
2707
2878
|
}
|
|
2708
2879
|
|
|
2709
2880
|
declare const backtest: {
|
|
@@ -2736,4 +2907,4 @@ declare const backtest: {
|
|
|
2736
2907
|
loggerService: LoggerService;
|
|
2737
2908
|
};
|
|
2738
2909
|
|
|
2739
|
-
export { Backtest, type CandleInterval, type EntityId, ExecutionContextService, type FrameInterval, type ICandleData, type IExchangeSchema, type IFrameSchema, type IPersistBase, type ISignalData, type ISignalDto, type ISignalRow, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, Live, MethodContextService, PersistBase, PersistSignalAdaper, type SignalInterval, type TPersistBase, type TPersistBaseCtor, addExchange, addFrame, addStrategy, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listenDone, listenDoneOnce, listenError, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, setLogger };
|
|
2910
|
+
export { Backtest, type CandleInterval, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type ICandleData, type IExchangeSchema, type IFrameSchema, type IPersistBase, type ISignalData, type ISignalDto, type ISignalRow, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, Live, MethodContextService, PersistBase, PersistSignalAdaper, type ProgressContract, type SignalInterval, type TPersistBase, type TPersistBaseCtor, addExchange, addFrame, addStrategy, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listStrategies, listenDone, listenDoneOnce, listenError, listenProgress, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, setLogger };
|