backtest-kit 7.7.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +1804 -1761
- package/build/index.cjs +292 -2
- package/build/index.mjs +292 -3
- package/package.json +86 -86
- package/types.d.ts +93 -2
package/build/index.mjs
CHANGED
|
@@ -3845,6 +3845,27 @@ class ClientExchange {
|
|
|
3845
3845
|
const vwap = sumPriceVolume / totalVolume;
|
|
3846
3846
|
return vwap;
|
|
3847
3847
|
}
|
|
3848
|
+
/**
|
|
3849
|
+
* Returns the close price of the last completed candle for the given interval.
|
|
3850
|
+
*
|
|
3851
|
+
* Fetches a single candle for the requested interval and returns its close price.
|
|
3852
|
+
*
|
|
3853
|
+
* @param symbol - Trading pair symbol
|
|
3854
|
+
* @param interval - Candle time interval (e.g., "1m", "1h")
|
|
3855
|
+
* @returns Promise resolving to close price of the last candle
|
|
3856
|
+
* @throws Error if no candles available
|
|
3857
|
+
*/
|
|
3858
|
+
async getClosePrice(symbol, interval) {
|
|
3859
|
+
this.params.logger.debug(`ClientExchange getClosePrice`, {
|
|
3860
|
+
symbol,
|
|
3861
|
+
interval,
|
|
3862
|
+
});
|
|
3863
|
+
const candles = await this.getCandles(symbol, interval, 1);
|
|
3864
|
+
if (candles.length === 0) {
|
|
3865
|
+
throw new Error(`ClientExchange getClosePrice: no candles data for symbol=${symbol}`);
|
|
3866
|
+
}
|
|
3867
|
+
return candles[candles.length - 1].close;
|
|
3868
|
+
}
|
|
3848
3869
|
/**
|
|
3849
3870
|
* Formats quantity according to exchange-specific rules for the given symbol.
|
|
3850
3871
|
* Applies proper decimal precision and rounding based on symbol's lot size filters.
|
|
@@ -4250,6 +4271,22 @@ class ExchangeConnectionService {
|
|
|
4250
4271
|
});
|
|
4251
4272
|
return await this.getExchange(this.methodContextService.context.exchangeName).getAveragePrice(symbol);
|
|
4252
4273
|
};
|
|
4274
|
+
/**
|
|
4275
|
+
* Returns the close price of the last completed candle for the given interval.
|
|
4276
|
+
*
|
|
4277
|
+
* Routes to exchange determined by methodContextService.context.exchangeName.
|
|
4278
|
+
*
|
|
4279
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
4280
|
+
* @param interval - Candle interval (e.g., "1h", "1d")
|
|
4281
|
+
* @returns Promise resolving to close price of the last candle
|
|
4282
|
+
*/
|
|
4283
|
+
this.getClosePrice = async (symbol, interval) => {
|
|
4284
|
+
this.loggerService.log("exchangeConnectionService getClosePrice", {
|
|
4285
|
+
symbol,
|
|
4286
|
+
interval,
|
|
4287
|
+
});
|
|
4288
|
+
return await this.getExchange(this.methodContextService.context.exchangeName).getClosePrice(symbol, interval);
|
|
4289
|
+
};
|
|
4253
4290
|
/**
|
|
4254
4291
|
* Formats price according to exchange-specific precision rules.
|
|
4255
4292
|
*
|
|
@@ -5488,6 +5525,10 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
|
|
|
5488
5525
|
_peak: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
5489
5526
|
_fall: { price: signal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
5490
5527
|
};
|
|
5528
|
+
{
|
|
5529
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(signalRow, signal.priceOpen);
|
|
5530
|
+
signalRow._fall = { price: signal.priceOpen, timestamp: currentTime, pnlPercentage, pnlCost, priceClose, priceOpen, pnlEntries };
|
|
5531
|
+
}
|
|
5491
5532
|
// Валидируем сигнал перед возвратом
|
|
5492
5533
|
validatePendingSignal(signalRow, currentPrice);
|
|
5493
5534
|
return signalRow;
|
|
@@ -5537,6 +5578,10 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
|
|
|
5537
5578
|
_peak: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
5538
5579
|
_fall: { price: currentPrice, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
5539
5580
|
};
|
|
5581
|
+
{
|
|
5582
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(signalRow, currentPrice);
|
|
5583
|
+
signalRow._fall = { price: currentPrice, timestamp: currentTime, pnlPercentage, pnlCost, priceClose, priceOpen, pnlEntries };
|
|
5584
|
+
}
|
|
5540
5585
|
// Валидируем сигнал перед возвратом
|
|
5541
5586
|
validatePendingSignal(signalRow, currentPrice);
|
|
5542
5587
|
return signalRow;
|
|
@@ -6249,6 +6294,10 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
6249
6294
|
_peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
|
|
6250
6295
|
_fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
|
|
6251
6296
|
};
|
|
6297
|
+
{
|
|
6298
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(activatedSignal, activatedSignal.priceOpen);
|
|
6299
|
+
activatedSignal._fall = { price: activatedSignal.priceOpen, timestamp: activationTime, pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen };
|
|
6300
|
+
}
|
|
6252
6301
|
// Sync open: if external system rejects — cancel scheduled signal instead of opening
|
|
6253
6302
|
const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(activationTime, activatedSignal.priceOpen, activatedSignal, self);
|
|
6254
6303
|
if (!syncOpenAllowed) {
|
|
@@ -7132,6 +7181,10 @@ const ACTIVATE_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, activat
|
|
|
7132
7181
|
_peak: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
|
|
7133
7182
|
_fall: { price: scheduled.priceOpen, timestamp: activationTime, pnlPercentage: 0, pnlCost: 0, pnlEntries: 0, priceClose: 0, priceOpen: 0 },
|
|
7134
7183
|
};
|
|
7184
|
+
{
|
|
7185
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(activatedSignal, activatedSignal.priceOpen);
|
|
7186
|
+
activatedSignal._fall = { price: activatedSignal.priceOpen, timestamp: activationTime, pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen };
|
|
7187
|
+
}
|
|
7135
7188
|
// Sync open: if external system rejects — cancel scheduled signal instead of opening
|
|
7136
7189
|
const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(activationTime, activatedSignal.priceOpen, activatedSignal, self);
|
|
7137
7190
|
if (!syncOpenAllowed) {
|
|
@@ -7329,6 +7382,10 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles, fra
|
|
|
7329
7382
|
_peak: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
7330
7383
|
_fall: { price: activatedSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage: 0, pnlCost: 0, priceClose: 0, priceOpen: 0, pnlEntries: 0 },
|
|
7331
7384
|
};
|
|
7385
|
+
{
|
|
7386
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(pendingSignal, pendingSignal.priceOpen);
|
|
7387
|
+
pendingSignal._fall = { price: pendingSignal.priceOpen, timestamp: candle.timestamp, pnlPercentage, pnlCost, priceClose, priceOpen, pnlEntries };
|
|
7388
|
+
}
|
|
7332
7389
|
// Sync open: if external system rejects — cancel scheduled signal instead of opening
|
|
7333
7390
|
const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(candle.timestamp, pendingSignal.priceOpen, pendingSignal, self);
|
|
7334
7391
|
if (!syncOpenAllowed) {
|
|
@@ -8773,6 +8830,10 @@ class ClientStrategy {
|
|
|
8773
8830
|
_peak: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, pnlEntries: 0, priceOpen: 0 },
|
|
8774
8831
|
_fall: { price: activatedSignal.priceOpen, timestamp: currentTime, pnlPercentage: 0, pnlCost: 0, priceClose: 0, pnlEntries: 0, priceOpen: 0 },
|
|
8775
8832
|
};
|
|
8833
|
+
{
|
|
8834
|
+
const { pnlPercentage, pnlCost, pnlEntries, priceClose, priceOpen } = toProfitLossDto(pendingSignal, pendingSignal.priceOpen);
|
|
8835
|
+
pendingSignal._fall = { price: pendingSignal.priceOpen, timestamp: currentTime, pnlPercentage, pnlCost, priceClose, pnlEntries, priceOpen };
|
|
8836
|
+
}
|
|
8776
8837
|
const syncOpenAllowed = await CALL_SIGNAL_SYNC_OPEN_FN(currentTime, currentPrice, pendingSignal, this);
|
|
8777
8838
|
if (!syncOpenAllowed) {
|
|
8778
8839
|
this.params.logger.info("ClientStrategy tick: user-activated signal rejected by sync", {
|
|
@@ -14840,6 +14901,34 @@ class ExchangeCoreService {
|
|
|
14840
14901
|
backtest,
|
|
14841
14902
|
});
|
|
14842
14903
|
};
|
|
14904
|
+
/**
|
|
14905
|
+
* Returns the close price of the last completed candle for the given interval with execution context.
|
|
14906
|
+
*
|
|
14907
|
+
* @param symbol - Trading pair symbol
|
|
14908
|
+
* @param interval - Candle interval (e.g., "1m", "1h")
|
|
14909
|
+
* @param when - Timestamp for context (used in backtest mode)
|
|
14910
|
+
* @param backtest - Whether running in backtest mode
|
|
14911
|
+
* @returns Promise resolving to close price of the last candle
|
|
14912
|
+
*/
|
|
14913
|
+
this.getClosePrice = async (symbol, interval, when, backtest) => {
|
|
14914
|
+
this.loggerService.log("exchangeCoreService getClosePrice", {
|
|
14915
|
+
symbol,
|
|
14916
|
+
interval,
|
|
14917
|
+
when,
|
|
14918
|
+
backtest,
|
|
14919
|
+
});
|
|
14920
|
+
if (!MethodContextService.hasContext()) {
|
|
14921
|
+
throw new Error("exchangeCoreService getClosePrice requires a method context");
|
|
14922
|
+
}
|
|
14923
|
+
await this.validate(this.methodContextService.context.exchangeName);
|
|
14924
|
+
return await ExecutionContextService.runInContext(async () => {
|
|
14925
|
+
return await this.exchangeConnectionService.getClosePrice(symbol, interval);
|
|
14926
|
+
}, {
|
|
14927
|
+
symbol,
|
|
14928
|
+
when,
|
|
14929
|
+
backtest,
|
|
14930
|
+
});
|
|
14931
|
+
};
|
|
14843
14932
|
/**
|
|
14844
14933
|
* Formats price with execution context.
|
|
14845
14934
|
*
|
|
@@ -19308,6 +19397,24 @@ const heat_columns = [
|
|
|
19308
19397
|
format: (data) => data.avgFallPnl !== null ? str(data.avgFallPnl, "%") : "N/A",
|
|
19309
19398
|
isVisible: () => true,
|
|
19310
19399
|
},
|
|
19400
|
+
{
|
|
19401
|
+
key: "sortinoRatio",
|
|
19402
|
+
label: "Sortino",
|
|
19403
|
+
format: (data) => data.sortinoRatio !== null ? str(data.sortinoRatio) : "N/A",
|
|
19404
|
+
isVisible: () => true,
|
|
19405
|
+
},
|
|
19406
|
+
{
|
|
19407
|
+
key: "calmarRatio",
|
|
19408
|
+
label: "Calmar",
|
|
19409
|
+
format: (data) => data.calmarRatio !== null ? str(data.calmarRatio) : "N/A",
|
|
19410
|
+
isVisible: () => true,
|
|
19411
|
+
},
|
|
19412
|
+
{
|
|
19413
|
+
key: "recoveryFactor",
|
|
19414
|
+
label: "Recovery",
|
|
19415
|
+
format: (data) => data.recoveryFactor !== null ? str(data.recoveryFactor) : "N/A",
|
|
19416
|
+
isVisible: () => true,
|
|
19417
|
+
},
|
|
19311
19418
|
];
|
|
19312
19419
|
|
|
19313
19420
|
/**
|
|
@@ -20870,6 +20977,30 @@ const walker_strategy_columns = [
|
|
|
20870
20977
|
: "N/A",
|
|
20871
20978
|
isVisible: () => true,
|
|
20872
20979
|
},
|
|
20980
|
+
{
|
|
20981
|
+
key: "sortinoRatio",
|
|
20982
|
+
label: "Sortino",
|
|
20983
|
+
format: (data) => data.stats.sortinoRatio !== null
|
|
20984
|
+
? `${data.stats.sortinoRatio.toFixed(3)}`
|
|
20985
|
+
: "N/A",
|
|
20986
|
+
isVisible: () => true,
|
|
20987
|
+
},
|
|
20988
|
+
{
|
|
20989
|
+
key: "calmarRatio",
|
|
20990
|
+
label: "Calmar",
|
|
20991
|
+
format: (data) => data.stats.calmarRatio !== null
|
|
20992
|
+
? `${data.stats.calmarRatio.toFixed(3)}`
|
|
20993
|
+
: "N/A",
|
|
20994
|
+
isVisible: () => true,
|
|
20995
|
+
},
|
|
20996
|
+
{
|
|
20997
|
+
key: "recoveryFactor",
|
|
20998
|
+
label: "Recovery",
|
|
20999
|
+
format: (data) => data.stats.recoveryFactor !== null
|
|
21000
|
+
? `${data.stats.recoveryFactor.toFixed(3)}`
|
|
21001
|
+
: "N/A",
|
|
21002
|
+
isVisible: () => true,
|
|
21003
|
+
},
|
|
20873
21004
|
{
|
|
20874
21005
|
key: "firstEventTime",
|
|
20875
21006
|
label: "First Event",
|
|
@@ -21419,13 +21550,13 @@ class ReportBase {
|
|
|
21419
21550
|
* Waits for drain event if write buffer is full.
|
|
21420
21551
|
* Times out after 15 seconds and returns TIMEOUT_SYMBOL.
|
|
21421
21552
|
*/
|
|
21422
|
-
this[_d] = timeout(async (line) => {
|
|
21553
|
+
this[_d] = queued(timeout(async (line) => {
|
|
21423
21554
|
if (!this._stream.write(line)) {
|
|
21424
21555
|
await new Promise((resolve) => {
|
|
21425
21556
|
this._stream.once("drain", resolve);
|
|
21426
21557
|
});
|
|
21427
21558
|
}
|
|
21428
|
-
}, 15000);
|
|
21559
|
+
}, 15000));
|
|
21429
21560
|
LOGGER_SERVICE$3.debug(REPORT_BASE_METHOD_NAME_CTOR, {
|
|
21430
21561
|
reportName: this.reportName,
|
|
21431
21562
|
baseDir,
|
|
@@ -21713,6 +21844,9 @@ let ReportStorage$a = class ReportStorage {
|
|
|
21713
21844
|
expectedYearlyReturns: null,
|
|
21714
21845
|
avgPeakPnl: null,
|
|
21715
21846
|
avgFallPnl: null,
|
|
21847
|
+
sortinoRatio: null,
|
|
21848
|
+
calmarRatio: null,
|
|
21849
|
+
recoveryFactor: null,
|
|
21716
21850
|
};
|
|
21717
21851
|
}
|
|
21718
21852
|
const totalSignals = this._signalList.length;
|
|
@@ -21746,6 +21880,16 @@ let ReportStorage$a = class ReportStorage {
|
|
|
21746
21880
|
// Calculate average peak and fall PNL across all signals
|
|
21747
21881
|
const avgPeakPnl = this._signalList.reduce((sum, s) => sum + (s.signal.peakProfit?.pnlPercentage ?? 0), 0) / totalSignals;
|
|
21748
21882
|
const avgFallPnl = this._signalList.reduce((sum, s) => sum + (s.signal.maxDrawdown?.pnlPercentage ?? 0), 0) / totalSignals;
|
|
21883
|
+
// Downside per signal: maxDrawdown.pnlPercentage captures the worst intra-trade dip
|
|
21884
|
+
const fallReturns = this._signalList.map((s) => s.signal.maxDrawdown?.pnlPercentage ?? 0);
|
|
21885
|
+
// Calculate Sortino Ratio: avgPnl / stdDev(maxDrawdown per signal)
|
|
21886
|
+
const fallVariance = fallReturns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / totalSignals;
|
|
21887
|
+
const fallDeviation = Math.sqrt(fallVariance);
|
|
21888
|
+
const sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
|
|
21889
|
+
// Avg absolute peak drawdown per signal — used as denominator for Calmar and Recovery
|
|
21890
|
+
const avgAbsFall = fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalSignals;
|
|
21891
|
+
const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
|
|
21892
|
+
const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
|
|
21749
21893
|
return {
|
|
21750
21894
|
signalList: this._signalList,
|
|
21751
21895
|
totalSignals,
|
|
@@ -21761,6 +21905,9 @@ let ReportStorage$a = class ReportStorage {
|
|
|
21761
21905
|
expectedYearlyReturns: isUnsafe$3(expectedYearlyReturns) ? null : expectedYearlyReturns,
|
|
21762
21906
|
avgPeakPnl: isUnsafe$3(avgPeakPnl) ? null : avgPeakPnl,
|
|
21763
21907
|
avgFallPnl: isUnsafe$3(avgFallPnl) ? null : avgFallPnl,
|
|
21908
|
+
sortinoRatio: isUnsafe$3(sortinoRatio) ? null : sortinoRatio,
|
|
21909
|
+
calmarRatio: isUnsafe$3(calmarRatio) ? null : calmarRatio,
|
|
21910
|
+
recoveryFactor: isUnsafe$3(recoveryFactor) ? null : recoveryFactor,
|
|
21764
21911
|
};
|
|
21765
21912
|
}
|
|
21766
21913
|
/**
|
|
@@ -21807,6 +21954,9 @@ let ReportStorage$a = class ReportStorage {
|
|
|
21807
21954
|
`**Expected Yearly Returns:** ${stats.expectedYearlyReturns === null ? "N/A" : `${stats.expectedYearlyReturns > 0 ? "+" : ""}${stats.expectedYearlyReturns.toFixed(2)}% (higher is better)`}`,
|
|
21808
21955
|
`**Avg Peak PNL:** ${stats.avgPeakPnl === null ? "N/A" : `${stats.avgPeakPnl > 0 ? "+" : ""}${stats.avgPeakPnl.toFixed(2)}% (higher is better)`}`,
|
|
21809
21956
|
`**Avg Max Drawdown PNL:** ${stats.avgFallPnl === null ? "N/A" : `${stats.avgFallPnl.toFixed(2)}% (closer to 0 is better)`}`,
|
|
21957
|
+
`**Sortino Ratio:** ${stats.sortinoRatio === null ? "N/A" : `${stats.sortinoRatio.toFixed(3)} (higher is better)`}`,
|
|
21958
|
+
`**Calmar Ratio:** ${stats.calmarRatio === null ? "N/A" : `${stats.calmarRatio.toFixed(3)} (higher is better)`}`,
|
|
21959
|
+
`**Recovery Factor:** ${stats.recoveryFactor === null ? "N/A" : `${stats.recoveryFactor.toFixed(3)} (higher is better)`}`,
|
|
21810
21960
|
].join("\n");
|
|
21811
21961
|
}
|
|
21812
21962
|
/**
|
|
@@ -22407,6 +22557,9 @@ let ReportStorage$9 = class ReportStorage {
|
|
|
22407
22557
|
expectedYearlyReturns: null,
|
|
22408
22558
|
avgPeakPnl: null,
|
|
22409
22559
|
avgFallPnl: null,
|
|
22560
|
+
sortinoRatio: null,
|
|
22561
|
+
calmarRatio: null,
|
|
22562
|
+
recoveryFactor: null,
|
|
22410
22563
|
};
|
|
22411
22564
|
}
|
|
22412
22565
|
const closedEvents = this._eventList.filter((e) => e.action === "closed");
|
|
@@ -22456,6 +22609,21 @@ let ReportStorage$9 = class ReportStorage {
|
|
|
22456
22609
|
const avgFallPnl = totalClosed > 0
|
|
22457
22610
|
? closedEvents.reduce((sum, e) => sum + (e.fallPnl || 0), 0) / totalClosed
|
|
22458
22611
|
: 0;
|
|
22612
|
+
// Downside per signal: fallPnl captures the worst intra-trade dip (maxDrawdown.pnlPercentage)
|
|
22613
|
+
const fallReturns = closedEvents.map((e) => e.fallPnl || 0);
|
|
22614
|
+
// Calculate Sortino Ratio: avgPnl / stdDev(maxDrawdown per signal)
|
|
22615
|
+
let sortinoRatio = 0;
|
|
22616
|
+
if (totalClosed > 0) {
|
|
22617
|
+
const fallVariance = fallReturns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / totalClosed;
|
|
22618
|
+
const fallDeviation = Math.sqrt(fallVariance);
|
|
22619
|
+
sortinoRatio = fallDeviation > 0 ? avgPnl / fallDeviation : 0;
|
|
22620
|
+
}
|
|
22621
|
+
// Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
|
|
22622
|
+
const avgAbsFall = totalClosed > 0
|
|
22623
|
+
? fallReturns.reduce((sum, r) => sum + Math.abs(r), 0) / totalClosed
|
|
22624
|
+
: 0;
|
|
22625
|
+
const calmarRatio = avgAbsFall > 0 ? expectedYearlyReturns / avgAbsFall : 0;
|
|
22626
|
+
const recoveryFactor = avgAbsFall > 0 ? totalPnl / avgAbsFall : 0;
|
|
22459
22627
|
return {
|
|
22460
22628
|
eventList: this._eventList,
|
|
22461
22629
|
totalEvents: this._eventList.length,
|
|
@@ -22472,6 +22640,9 @@ let ReportStorage$9 = class ReportStorage {
|
|
|
22472
22640
|
expectedYearlyReturns: isUnsafe$2(expectedYearlyReturns) ? null : expectedYearlyReturns,
|
|
22473
22641
|
avgPeakPnl: isUnsafe$2(avgPeakPnl) ? null : avgPeakPnl,
|
|
22474
22642
|
avgFallPnl: isUnsafe$2(avgFallPnl) ? null : avgFallPnl,
|
|
22643
|
+
sortinoRatio: isUnsafe$2(sortinoRatio) ? null : sortinoRatio,
|
|
22644
|
+
calmarRatio: isUnsafe$2(calmarRatio) ? null : calmarRatio,
|
|
22645
|
+
recoveryFactor: isUnsafe$2(recoveryFactor) ? null : recoveryFactor,
|
|
22475
22646
|
};
|
|
22476
22647
|
}
|
|
22477
22648
|
/**
|
|
@@ -22518,6 +22689,9 @@ let ReportStorage$9 = class ReportStorage {
|
|
|
22518
22689
|
`**Expected Yearly Returns:** ${stats.expectedYearlyReturns === null ? "N/A" : `${stats.expectedYearlyReturns > 0 ? "+" : ""}${stats.expectedYearlyReturns.toFixed(2)}% (higher is better)`}`,
|
|
22519
22690
|
`**Avg Peak PNL:** ${stats.avgPeakPnl === null ? "N/A" : `${stats.avgPeakPnl > 0 ? "+" : ""}${stats.avgPeakPnl.toFixed(2)}% (higher is better)`}`,
|
|
22520
22691
|
`**Avg Max Drawdown PNL:** ${stats.avgFallPnl === null ? "N/A" : `${stats.avgFallPnl.toFixed(2)}% (closer to 0 is better)`}`,
|
|
22692
|
+
`**Sortino Ratio:** ${stats.sortinoRatio === null ? "N/A" : `${stats.sortinoRatio.toFixed(3)} (higher is better)`}`,
|
|
22693
|
+
`**Calmar Ratio:** ${stats.calmarRatio === null ? "N/A" : `${stats.calmarRatio.toFixed(3)} (higher is better)`}`,
|
|
22694
|
+
`**Recovery Factor:** ${stats.recoveryFactor === null ? "N/A" : `${stats.recoveryFactor.toFixed(3)} (higher is better)`}`,
|
|
22521
22695
|
].join("\n");
|
|
22522
22696
|
}
|
|
22523
22697
|
/**
|
|
@@ -23963,6 +24137,9 @@ let ReportStorage$7 = class ReportStorage {
|
|
|
23963
24137
|
"",
|
|
23964
24138
|
`**Best ${results.metric}:** ${formatMetric(results.bestMetric)}`,
|
|
23965
24139
|
`**Total Signals:** ${bestStrategySignals}`,
|
|
24140
|
+
`**Sortino Ratio:** ${results.bestStats?.sortinoRatio != null ? `${results.bestStats.sortinoRatio.toFixed(3)} (higher is better)` : "N/A"}`,
|
|
24141
|
+
`**Calmar Ratio:** ${results.bestStats?.calmarRatio != null ? `${results.bestStats.calmarRatio.toFixed(3)} (higher is better)` : "N/A"}`,
|
|
24142
|
+
`**Recovery Factor:** ${results.bestStats?.recoveryFactor != null ? `${results.bestStats.recoveryFactor.toFixed(3)} (higher is better)` : "N/A"}`,
|
|
23966
24143
|
"",
|
|
23967
24144
|
"## Top Strategies Comparison",
|
|
23968
24145
|
"",
|
|
@@ -24429,6 +24606,27 @@ class HeatmapStorage {
|
|
|
24429
24606
|
avgPeakPnl = signals.reduce((acc, s) => acc + (s.signal.peakProfit?.pnlPercentage ?? 0), 0) / signals.length;
|
|
24430
24607
|
avgFallPnl = signals.reduce((acc, s) => acc + (s.signal.maxDrawdown?.pnlPercentage ?? 0), 0) / signals.length;
|
|
24431
24608
|
}
|
|
24609
|
+
// Downside per signal: maxDrawdown.pnlPercentage captures the worst intra-trade dip
|
|
24610
|
+
const fallReturns = signals.map((s) => s.signal.maxDrawdown?.pnlPercentage ?? 0);
|
|
24611
|
+
// Calculate Sortino Ratio: avgPnl / stdDev(maxDrawdown per signal)
|
|
24612
|
+
let sortinoRatio = null;
|
|
24613
|
+
if (signals.length > 0 && avgPnl !== null) {
|
|
24614
|
+
const fallVariance = fallReturns.reduce((acc, r) => acc + Math.pow(r, 2), 0) / signals.length;
|
|
24615
|
+
const fallDeviation = Math.sqrt(fallVariance);
|
|
24616
|
+
if (fallDeviation > 0) {
|
|
24617
|
+
sortinoRatio = avgPnl / fallDeviation;
|
|
24618
|
+
}
|
|
24619
|
+
}
|
|
24620
|
+
// Avg absolute peak drawdown per signal — denominator for Calmar and Recovery
|
|
24621
|
+
const avgAbsFall = signals.length > 0
|
|
24622
|
+
? fallReturns.reduce((acc, r) => acc + Math.abs(r), 0) / signals.length
|
|
24623
|
+
: 0;
|
|
24624
|
+
let calmarRatio = null;
|
|
24625
|
+
let recoveryFactor = null;
|
|
24626
|
+
if (avgAbsFall > 0 && totalPnl !== null) {
|
|
24627
|
+
calmarRatio = totalPnl / avgAbsFall;
|
|
24628
|
+
recoveryFactor = totalPnl / avgAbsFall;
|
|
24629
|
+
}
|
|
24432
24630
|
// Apply safe math checks
|
|
24433
24631
|
if (isUnsafe(winRate))
|
|
24434
24632
|
winRate = null;
|
|
@@ -24454,6 +24652,12 @@ class HeatmapStorage {
|
|
|
24454
24652
|
avgPeakPnl = null;
|
|
24455
24653
|
if (isUnsafe(avgFallPnl))
|
|
24456
24654
|
avgFallPnl = null;
|
|
24655
|
+
if (isUnsafe(sortinoRatio))
|
|
24656
|
+
sortinoRatio = null;
|
|
24657
|
+
if (isUnsafe(calmarRatio))
|
|
24658
|
+
calmarRatio = null;
|
|
24659
|
+
if (isUnsafe(recoveryFactor))
|
|
24660
|
+
recoveryFactor = null;
|
|
24457
24661
|
return {
|
|
24458
24662
|
symbol,
|
|
24459
24663
|
totalPnl,
|
|
@@ -24473,6 +24677,9 @@ class HeatmapStorage {
|
|
|
24473
24677
|
expectancy,
|
|
24474
24678
|
avgPeakPnl,
|
|
24475
24679
|
avgFallPnl,
|
|
24680
|
+
sortinoRatio,
|
|
24681
|
+
calmarRatio,
|
|
24682
|
+
recoveryFactor,
|
|
24476
24683
|
};
|
|
24477
24684
|
}
|
|
24478
24685
|
/**
|
|
@@ -29339,6 +29546,9 @@ class WalkerReportService {
|
|
|
29339
29546
|
annualizedSharpeRatio: data.stats.annualizedSharpeRatio,
|
|
29340
29547
|
certaintyRatio: data.stats.certaintyRatio,
|
|
29341
29548
|
expectedYearlyReturns: data.stats.expectedYearlyReturns,
|
|
29549
|
+
sortinoRatio: data.stats.sortinoRatio,
|
|
29550
|
+
calmarRatio: data.stats.calmarRatio,
|
|
29551
|
+
recoveryFactor: data.stats.recoveryFactor,
|
|
29342
29552
|
firstEventTime,
|
|
29343
29553
|
lastEventTime,
|
|
29344
29554
|
}, {
|
|
@@ -33528,6 +33738,7 @@ async function getBacktestTimeframe(symbol) {
|
|
|
33528
33738
|
|
|
33529
33739
|
const EXCHANGE_METHOD_NAME_GET_CANDLES = "ExchangeUtils.getCandles";
|
|
33530
33740
|
const EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE = "ExchangeUtils.getAveragePrice";
|
|
33741
|
+
const EXCHANGE_METHOD_NAME_GET_CLOSE_PRICE = "ExchangeUtils.getClosePrice";
|
|
33531
33742
|
const EXCHANGE_METHOD_NAME_FORMAT_QUANTITY = "ExchangeUtils.formatQuantity";
|
|
33532
33743
|
const EXCHANGE_METHOD_NAME_FORMAT_PRICE = "ExchangeUtils.formatPrice";
|
|
33533
33744
|
const EXCHANGE_METHOD_NAME_GET_ORDER_BOOK = "ExchangeUtils.getOrderBook";
|
|
@@ -33885,6 +34096,35 @@ class ExchangeInstance {
|
|
|
33885
34096
|
const vwap = sumPriceVolume / totalVolume;
|
|
33886
34097
|
return vwap;
|
|
33887
34098
|
};
|
|
34099
|
+
/**
|
|
34100
|
+
* Returns the close price of the last completed candle for the given interval.
|
|
34101
|
+
*
|
|
34102
|
+
* Fetches a single candle for the requested interval and returns its close price.
|
|
34103
|
+
*
|
|
34104
|
+
* @param symbol - Trading pair symbol
|
|
34105
|
+
* @param interval - Candle time interval (e.g., "1m", "1h")
|
|
34106
|
+
* @returns Promise resolving to close price of the last candle
|
|
34107
|
+
* @throws Error if no candles available
|
|
34108
|
+
*
|
|
34109
|
+
* @example
|
|
34110
|
+
* ```typescript
|
|
34111
|
+
* const instance = new ExchangeInstance("binance");
|
|
34112
|
+
* const close = await instance.getClosePrice("BTCUSDT", "1h");
|
|
34113
|
+
* console.log(close); // 50125.43
|
|
34114
|
+
* ```
|
|
34115
|
+
*/
|
|
34116
|
+
this.getClosePrice = async (symbol, interval) => {
|
|
34117
|
+
backtest.loggerService.debug(`ExchangeInstance getClosePrice`, {
|
|
34118
|
+
exchangeName: this.exchangeName,
|
|
34119
|
+
symbol,
|
|
34120
|
+
interval,
|
|
34121
|
+
});
|
|
34122
|
+
const candles = await this.getCandles(symbol, interval, 1);
|
|
34123
|
+
if (candles.length === 0) {
|
|
34124
|
+
throw new Error(`ExchangeInstance getClosePrice: no candles data for symbol=${symbol}`);
|
|
34125
|
+
}
|
|
34126
|
+
return candles[candles.length - 1].close;
|
|
34127
|
+
};
|
|
33888
34128
|
/**
|
|
33889
34129
|
* Format quantity according to exchange precision rules.
|
|
33890
34130
|
*
|
|
@@ -34242,6 +34482,28 @@ class ExchangeUtils {
|
|
|
34242
34482
|
const instance = this._getInstance(context.exchangeName);
|
|
34243
34483
|
return await instance.getAveragePrice(symbol);
|
|
34244
34484
|
};
|
|
34485
|
+
/**
|
|
34486
|
+
* Returns the close price of the last completed candle for the given interval.
|
|
34487
|
+
*
|
|
34488
|
+
* @param symbol - Trading pair symbol
|
|
34489
|
+
* @param interval - Candle time interval (e.g., "1m", "1h")
|
|
34490
|
+
* @param context - Execution context with exchange name
|
|
34491
|
+
* @returns Promise resolving to close price of the last candle
|
|
34492
|
+
* @throws Error if no candles available
|
|
34493
|
+
*
|
|
34494
|
+
* @example
|
|
34495
|
+
* ```typescript
|
|
34496
|
+
* const close = await Exchange.getClosePrice("BTCUSDT", "1h", {
|
|
34497
|
+
* exchangeName: "binance"
|
|
34498
|
+
* });
|
|
34499
|
+
* console.log(close); // 50125.43
|
|
34500
|
+
* ```
|
|
34501
|
+
*/
|
|
34502
|
+
this.getClosePrice = async (symbol, interval, context) => {
|
|
34503
|
+
backtest.exchangeValidationService.validate(context.exchangeName, EXCHANGE_METHOD_NAME_GET_CLOSE_PRICE);
|
|
34504
|
+
const instance = this._getInstance(context.exchangeName);
|
|
34505
|
+
return await instance.getClosePrice(symbol, interval);
|
|
34506
|
+
};
|
|
34245
34507
|
/**
|
|
34246
34508
|
* Format quantity according to exchange precision rules.
|
|
34247
34509
|
*
|
|
@@ -34828,6 +35090,7 @@ function getActionSchema(actionName) {
|
|
|
34828
35090
|
|
|
34829
35091
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
34830
35092
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
35093
|
+
const GET_CLOSE_PRICE_METHOD_NAME = "exchange.getClosePrice";
|
|
34831
35094
|
const FORMAT_PRICE_METHOD_NAME = "exchange.formatPrice";
|
|
34832
35095
|
const FORMAT_QUANTITY_METHOD_NAME = "exchange.formatQuantity";
|
|
34833
35096
|
const GET_DATE_METHOD_NAME = "exchange.getDate";
|
|
@@ -34925,6 +35188,32 @@ async function getAveragePrice(symbol) {
|
|
|
34925
35188
|
}
|
|
34926
35189
|
return await backtest.exchangeConnectionService.getAveragePrice(symbol);
|
|
34927
35190
|
}
|
|
35191
|
+
/**
|
|
35192
|
+
* Returns the close price of the last completed candle for the given interval.
|
|
35193
|
+
*
|
|
35194
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
35195
|
+
* @param interval - Candle interval ("1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "8h")
|
|
35196
|
+
* @returns Promise resolving to close price of the last candle
|
|
35197
|
+
*
|
|
35198
|
+
* @example
|
|
35199
|
+
* ```typescript
|
|
35200
|
+
* const close = await getClosePrice("BTCUSDT", "1h");
|
|
35201
|
+
* console.log(close); // 50125.43
|
|
35202
|
+
* ```
|
|
35203
|
+
*/
|
|
35204
|
+
async function getClosePrice(symbol, interval) {
|
|
35205
|
+
backtest.loggerService.info(GET_CLOSE_PRICE_METHOD_NAME, {
|
|
35206
|
+
symbol,
|
|
35207
|
+
interval,
|
|
35208
|
+
});
|
|
35209
|
+
if (!ExecutionContextService.hasContext()) {
|
|
35210
|
+
throw new Error("getClosePrice requires an execution context");
|
|
35211
|
+
}
|
|
35212
|
+
if (!MethodContextService.hasContext()) {
|
|
35213
|
+
throw new Error("getClosePrice requires a method context");
|
|
35214
|
+
}
|
|
35215
|
+
return await backtest.exchangeConnectionService.getClosePrice(symbol, interval);
|
|
35216
|
+
}
|
|
34928
35217
|
/**
|
|
34929
35218
|
* Formats a price value according to exchange rules.
|
|
34930
35219
|
*
|
|
@@ -61557,4 +61846,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
61557
61846
|
return !errors.length;
|
|
61558
61847
|
};
|
|
61559
61848
|
|
|
61560
|
-
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRecentAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSessionAdapter, PersistSignalAdapter, PersistStateAdapter, PersistStorageAdapter, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|
|
61849
|
+
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRecentAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSessionAdapter, PersistSignalAdapter, PersistStateAdapter, PersistStorageAdapter, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getClosePrice, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|