backtest-kit 1.5.30 → 1.5.31

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/build/index.cjs CHANGED
@@ -1438,7 +1438,7 @@ class LoggerService {
1438
1438
  }
1439
1439
  }
1440
1440
 
1441
- const INTERVAL_MINUTES$2 = {
1441
+ const INTERVAL_MINUTES$3 = {
1442
1442
  "1m": 1,
1443
1443
  "3m": 3,
1444
1444
  "5m": 5,
@@ -1583,7 +1583,7 @@ class ClientExchange {
1583
1583
  interval,
1584
1584
  limit,
1585
1585
  });
1586
- const step = INTERVAL_MINUTES$2[interval];
1586
+ const step = INTERVAL_MINUTES$3[interval];
1587
1587
  const adjust = step * limit - step;
1588
1588
  if (!adjust) {
1589
1589
  throw new Error(`ClientExchange unknown time adjust for interval=${interval}`);
@@ -1621,7 +1621,7 @@ class ClientExchange {
1621
1621
  const since = new Date(this.params.execution.context.when.getTime());
1622
1622
  const now = Date.now();
1623
1623
  // Вычисляем конечное время запроса
1624
- const step = INTERVAL_MINUTES$2[interval];
1624
+ const step = INTERVAL_MINUTES$3[interval];
1625
1625
  const endTime = since.getTime() + limit * step * 60 * 1000;
1626
1626
  // Проверяем что запрошенный период не заходит за Date.now()
1627
1627
  if (endTime > now) {
@@ -2845,7 +2845,7 @@ var emitters = /*#__PURE__*/Object.freeze({
2845
2845
  walkerStopSubject: walkerStopSubject
2846
2846
  });
2847
2847
 
2848
- const INTERVAL_MINUTES$1 = {
2848
+ const INTERVAL_MINUTES$2 = {
2849
2849
  "1m": 1,
2850
2850
  "3m": 3,
2851
2851
  "5m": 5,
@@ -3063,7 +3063,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
3063
3063
  }
3064
3064
  const currentTime = self.params.execution.context.when.getTime();
3065
3065
  {
3066
- const intervalMinutes = INTERVAL_MINUTES$1[self.params.interval];
3066
+ const intervalMinutes = INTERVAL_MINUTES$2[self.params.interval];
3067
3067
  const intervalMs = intervalMinutes * 60 * 1000;
3068
3068
  // Проверяем что прошел нужный интервал с последнего getSignal
3069
3069
  if (self._lastSignalTimestamp !== null &&
@@ -4811,7 +4811,7 @@ class StrategyConnectionService {
4811
4811
  * Maps FrameInterval to minutes for timestamp calculation.
4812
4812
  * Used to generate timeframe arrays with proper spacing.
4813
4813
  */
4814
- const INTERVAL_MINUTES = {
4814
+ const INTERVAL_MINUTES$1 = {
4815
4815
  "1m": 1,
4816
4816
  "3m": 3,
4817
4817
  "5m": 5,
@@ -4840,7 +4840,7 @@ const GET_TIMEFRAME_FN = async (symbol, self) => {
4840
4840
  symbol,
4841
4841
  });
4842
4842
  const { interval, startDate, endDate } = self.params;
4843
- const intervalMinutes = INTERVAL_MINUTES[interval];
4843
+ const intervalMinutes = INTERVAL_MINUTES$1[interval];
4844
4844
  if (!intervalMinutes) {
4845
4845
  throw new Error(`ClientFrame unknown interval: ${interval}`);
4846
4846
  }
@@ -18134,8 +18134,21 @@ class ConstantUtils {
18134
18134
  const Constant = new ConstantUtils();
18135
18135
 
18136
18136
  const EXCHANGE_METHOD_NAME_GET_CANDLES = "ExchangeUtils.getCandles";
18137
+ const EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE = "ExchangeUtils.getAveragePrice";
18137
18138
  const EXCHANGE_METHOD_NAME_FORMAT_QUANTITY = "ExchangeUtils.formatQuantity";
18138
18139
  const EXCHANGE_METHOD_NAME_FORMAT_PRICE = "ExchangeUtils.formatPrice";
18140
+ const INTERVAL_MINUTES = {
18141
+ "1m": 1,
18142
+ "3m": 3,
18143
+ "5m": 5,
18144
+ "15m": 15,
18145
+ "30m": 30,
18146
+ "1h": 60,
18147
+ "2h": 120,
18148
+ "4h": 240,
18149
+ "6h": 360,
18150
+ "8h": 480,
18151
+ };
18139
18152
  /**
18140
18153
  * Instance class for exchange operations on a specific exchange.
18141
18154
  *
@@ -18147,7 +18160,8 @@ const EXCHANGE_METHOD_NAME_FORMAT_PRICE = "ExchangeUtils.formatPrice";
18147
18160
  * ```typescript
18148
18161
  * const instance = new ExchangeInstance("binance");
18149
18162
  *
18150
- * const candles = await instance.getCandles("BTCUSDT", "1m", new Date(), 100);
18163
+ * const candles = await instance.getCandles("BTCUSDT", "1m", 100);
18164
+ * const vwap = await instance.getAveragePrice("BTCUSDT");
18151
18165
  * const formattedQty = await instance.formatQuantity("BTCUSDT", 0.001);
18152
18166
  * const formattedPrice = await instance.formatPrice("BTCUSDT", 50000.123);
18153
18167
  * ```
@@ -18163,27 +18177,88 @@ class ExchangeInstance {
18163
18177
  /**
18164
18178
  * Fetch candles from data source (API or database).
18165
18179
  *
18180
+ * Automatically calculates the start date based on Date.now() and the requested interval/limit.
18181
+ * Uses the same logic as ClientExchange to ensure backwards compatibility.
18182
+ *
18166
18183
  * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
18167
18184
  * @param interval - Candle time interval (e.g., "1m", "1h")
18168
- * @param since - Start date for candle fetching
18169
18185
  * @param limit - Maximum number of candles to fetch
18170
18186
  * @returns Promise resolving to array of OHLCV candle data
18171
18187
  *
18172
18188
  * @example
18173
18189
  * ```typescript
18174
18190
  * const instance = new ExchangeInstance("binance");
18175
- * const candles = await instance.getCandles("BTCUSDT", "1m", new Date(), 100);
18191
+ * const candles = await instance.getCandles("BTCUSDT", "1m", 100);
18176
18192
  * ```
18177
18193
  */
18178
- this.getCandles = async (symbol, interval, since, limit) => {
18194
+ this.getCandles = async (symbol, interval, limit) => {
18179
18195
  backtest$1.loggerService.info(EXCHANGE_METHOD_NAME_GET_CANDLES, {
18180
18196
  exchangeName: this.exchangeName,
18181
18197
  symbol,
18182
18198
  interval,
18183
- since,
18184
18199
  limit,
18185
18200
  });
18186
- return await this._schema.getCandles(symbol, interval, since, limit);
18201
+ const step = INTERVAL_MINUTES[interval];
18202
+ const adjust = step * limit - step;
18203
+ if (!adjust) {
18204
+ throw new Error(`ExchangeInstance unknown time adjust for interval=${interval}`);
18205
+ }
18206
+ const when = new Date(Date.now());
18207
+ const since = new Date(when.getTime() - adjust * 60 * 1000);
18208
+ const data = await this._schema.getCandles(symbol, interval, since, limit);
18209
+ // Filter candles to strictly match the requested range
18210
+ const whenTimestamp = when.getTime();
18211
+ const sinceTimestamp = since.getTime();
18212
+ const filteredData = data.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
18213
+ if (filteredData.length < limit) {
18214
+ backtest$1.loggerService.warn(`ExchangeInstance Expected ${limit} candles, got ${filteredData.length}`);
18215
+ }
18216
+ return filteredData;
18217
+ };
18218
+ /**
18219
+ * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
18220
+ * The number of candles is configurable via GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT.
18221
+ *
18222
+ * Formula:
18223
+ * - Typical Price = (high + low + close) / 3
18224
+ * - VWAP = sum(typical_price * volume) / sum(volume)
18225
+ *
18226
+ * If volume is zero, returns simple average of close prices.
18227
+ *
18228
+ * @param symbol - Trading pair symbol
18229
+ * @returns Promise resolving to VWAP price
18230
+ * @throws Error if no candles available
18231
+ *
18232
+ * @example
18233
+ * ```typescript
18234
+ * const instance = new ExchangeInstance("binance");
18235
+ * const vwap = await instance.getAveragePrice("BTCUSDT");
18236
+ * console.log(vwap); // 50125.43
18237
+ * ```
18238
+ */
18239
+ this.getAveragePrice = async (symbol) => {
18240
+ backtest$1.loggerService.debug(`ExchangeInstance getAveragePrice`, {
18241
+ exchangeName: this.exchangeName,
18242
+ symbol,
18243
+ });
18244
+ const candles = await this.getCandles(symbol, "1m", GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT);
18245
+ if (candles.length === 0) {
18246
+ throw new Error(`ExchangeInstance getAveragePrice: no candles data for symbol=${symbol}`);
18247
+ }
18248
+ // VWAP (Volume Weighted Average Price)
18249
+ // Используем типичную цену (typical price) = (high + low + close) / 3
18250
+ const sumPriceVolume = candles.reduce((acc, candle) => {
18251
+ const typicalPrice = (candle.high + candle.low + candle.close) / 3;
18252
+ return acc + typicalPrice * candle.volume;
18253
+ }, 0);
18254
+ const totalVolume = candles.reduce((acc, candle) => acc + candle.volume, 0);
18255
+ if (totalVolume === 0) {
18256
+ // Если объем нулевой, возвращаем простое среднее close цен
18257
+ const sum = candles.reduce((acc, candle) => acc + candle.close, 0);
18258
+ return sum / candles.length;
18259
+ }
18260
+ const vwap = sumPriceVolume / totalVolume;
18261
+ return vwap;
18187
18262
  };
18188
18263
  /**
18189
18264
  * Format quantity according to exchange precision rules.
@@ -18242,7 +18317,10 @@ class ExchangeInstance {
18242
18317
  * ```typescript
18243
18318
  * import { Exchange } from "./classes/Exchange";
18244
18319
  *
18245
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
18320
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
18321
+ * exchangeName: "binance"
18322
+ * });
18323
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
18246
18324
  * exchangeName: "binance"
18247
18325
  * });
18248
18326
  * const formatted = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -18260,17 +18338,31 @@ class ExchangeUtils {
18260
18338
  /**
18261
18339
  * Fetch candles from data source (API or database).
18262
18340
  *
18341
+ * Automatically calculates the start date based on Date.now() and the requested interval/limit.
18342
+ * Uses the same logic as ClientExchange to ensure backwards compatibility.
18343
+ *
18263
18344
  * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
18264
18345
  * @param interval - Candle time interval (e.g., "1m", "1h")
18265
- * @param since - Start date for candle fetching
18266
18346
  * @param limit - Maximum number of candles to fetch
18267
18347
  * @param context - Execution context with exchange name
18268
18348
  * @returns Promise resolving to array of OHLCV candle data
18269
18349
  */
18270
- this.getCandles = async (symbol, interval, since, limit, context) => {
18350
+ this.getCandles = async (symbol, interval, limit, context) => {
18271
18351
  backtest$1.exchangeValidationService.validate(context.exchangeName, EXCHANGE_METHOD_NAME_GET_CANDLES);
18272
18352
  const instance = this._getInstance(context.exchangeName);
18273
- return await instance.getCandles(symbol, interval, since, limit);
18353
+ return await instance.getCandles(symbol, interval, limit);
18354
+ };
18355
+ /**
18356
+ * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
18357
+ *
18358
+ * @param symbol - Trading pair symbol
18359
+ * @param context - Execution context with exchange name
18360
+ * @returns Promise resolving to VWAP price
18361
+ */
18362
+ this.getAveragePrice = async (symbol, context) => {
18363
+ backtest$1.exchangeValidationService.validate(context.exchangeName, EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE);
18364
+ const instance = this._getInstance(context.exchangeName);
18365
+ return await instance.getAveragePrice(symbol);
18274
18366
  };
18275
18367
  /**
18276
18368
  * Format quantity according to exchange precision rules.
@@ -18308,7 +18400,10 @@ class ExchangeUtils {
18308
18400
  * import { Exchange } from "./classes/Exchange";
18309
18401
  *
18310
18402
  * // Using static-like API with context
18311
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
18403
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
18404
+ * exchangeName: "binance"
18405
+ * });
18406
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
18312
18407
  * exchangeName: "binance"
18313
18408
  * });
18314
18409
  * const qty = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -18320,7 +18415,8 @@ class ExchangeUtils {
18320
18415
  *
18321
18416
  * // Using instance API (no context needed, exchange set in constructor)
18322
18417
  * const binance = new ExchangeInstance("binance");
18323
- * const candles2 = await binance.getCandles("BTCUSDT", "1m", new Date(), 100);
18418
+ * const candles2 = await binance.getCandles("BTCUSDT", "1m", 100);
18419
+ * const vwap2 = await binance.getAveragePrice("BTCUSDT");
18324
18420
  * ```
18325
18421
  */
18326
18422
  const Exchange = new ExchangeUtils();
package/build/index.mjs CHANGED
@@ -1436,7 +1436,7 @@ class LoggerService {
1436
1436
  }
1437
1437
  }
1438
1438
 
1439
- const INTERVAL_MINUTES$2 = {
1439
+ const INTERVAL_MINUTES$3 = {
1440
1440
  "1m": 1,
1441
1441
  "3m": 3,
1442
1442
  "5m": 5,
@@ -1581,7 +1581,7 @@ class ClientExchange {
1581
1581
  interval,
1582
1582
  limit,
1583
1583
  });
1584
- const step = INTERVAL_MINUTES$2[interval];
1584
+ const step = INTERVAL_MINUTES$3[interval];
1585
1585
  const adjust = step * limit - step;
1586
1586
  if (!adjust) {
1587
1587
  throw new Error(`ClientExchange unknown time adjust for interval=${interval}`);
@@ -1619,7 +1619,7 @@ class ClientExchange {
1619
1619
  const since = new Date(this.params.execution.context.when.getTime());
1620
1620
  const now = Date.now();
1621
1621
  // Вычисляем конечное время запроса
1622
- const step = INTERVAL_MINUTES$2[interval];
1622
+ const step = INTERVAL_MINUTES$3[interval];
1623
1623
  const endTime = since.getTime() + limit * step * 60 * 1000;
1624
1624
  // Проверяем что запрошенный период не заходит за Date.now()
1625
1625
  if (endTime > now) {
@@ -2843,7 +2843,7 @@ var emitters = /*#__PURE__*/Object.freeze({
2843
2843
  walkerStopSubject: walkerStopSubject
2844
2844
  });
2845
2845
 
2846
- const INTERVAL_MINUTES$1 = {
2846
+ const INTERVAL_MINUTES$2 = {
2847
2847
  "1m": 1,
2848
2848
  "3m": 3,
2849
2849
  "5m": 5,
@@ -3061,7 +3061,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
3061
3061
  }
3062
3062
  const currentTime = self.params.execution.context.when.getTime();
3063
3063
  {
3064
- const intervalMinutes = INTERVAL_MINUTES$1[self.params.interval];
3064
+ const intervalMinutes = INTERVAL_MINUTES$2[self.params.interval];
3065
3065
  const intervalMs = intervalMinutes * 60 * 1000;
3066
3066
  // Проверяем что прошел нужный интервал с последнего getSignal
3067
3067
  if (self._lastSignalTimestamp !== null &&
@@ -4809,7 +4809,7 @@ class StrategyConnectionService {
4809
4809
  * Maps FrameInterval to minutes for timestamp calculation.
4810
4810
  * Used to generate timeframe arrays with proper spacing.
4811
4811
  */
4812
- const INTERVAL_MINUTES = {
4812
+ const INTERVAL_MINUTES$1 = {
4813
4813
  "1m": 1,
4814
4814
  "3m": 3,
4815
4815
  "5m": 5,
@@ -4838,7 +4838,7 @@ const GET_TIMEFRAME_FN = async (symbol, self) => {
4838
4838
  symbol,
4839
4839
  });
4840
4840
  const { interval, startDate, endDate } = self.params;
4841
- const intervalMinutes = INTERVAL_MINUTES[interval];
4841
+ const intervalMinutes = INTERVAL_MINUTES$1[interval];
4842
4842
  if (!intervalMinutes) {
4843
4843
  throw new Error(`ClientFrame unknown interval: ${interval}`);
4844
4844
  }
@@ -18132,8 +18132,21 @@ class ConstantUtils {
18132
18132
  const Constant = new ConstantUtils();
18133
18133
 
18134
18134
  const EXCHANGE_METHOD_NAME_GET_CANDLES = "ExchangeUtils.getCandles";
18135
+ const EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE = "ExchangeUtils.getAveragePrice";
18135
18136
  const EXCHANGE_METHOD_NAME_FORMAT_QUANTITY = "ExchangeUtils.formatQuantity";
18136
18137
  const EXCHANGE_METHOD_NAME_FORMAT_PRICE = "ExchangeUtils.formatPrice";
18138
+ const INTERVAL_MINUTES = {
18139
+ "1m": 1,
18140
+ "3m": 3,
18141
+ "5m": 5,
18142
+ "15m": 15,
18143
+ "30m": 30,
18144
+ "1h": 60,
18145
+ "2h": 120,
18146
+ "4h": 240,
18147
+ "6h": 360,
18148
+ "8h": 480,
18149
+ };
18137
18150
  /**
18138
18151
  * Instance class for exchange operations on a specific exchange.
18139
18152
  *
@@ -18145,7 +18158,8 @@ const EXCHANGE_METHOD_NAME_FORMAT_PRICE = "ExchangeUtils.formatPrice";
18145
18158
  * ```typescript
18146
18159
  * const instance = new ExchangeInstance("binance");
18147
18160
  *
18148
- * const candles = await instance.getCandles("BTCUSDT", "1m", new Date(), 100);
18161
+ * const candles = await instance.getCandles("BTCUSDT", "1m", 100);
18162
+ * const vwap = await instance.getAveragePrice("BTCUSDT");
18149
18163
  * const formattedQty = await instance.formatQuantity("BTCUSDT", 0.001);
18150
18164
  * const formattedPrice = await instance.formatPrice("BTCUSDT", 50000.123);
18151
18165
  * ```
@@ -18161,27 +18175,88 @@ class ExchangeInstance {
18161
18175
  /**
18162
18176
  * Fetch candles from data source (API or database).
18163
18177
  *
18178
+ * Automatically calculates the start date based on Date.now() and the requested interval/limit.
18179
+ * Uses the same logic as ClientExchange to ensure backwards compatibility.
18180
+ *
18164
18181
  * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
18165
18182
  * @param interval - Candle time interval (e.g., "1m", "1h")
18166
- * @param since - Start date for candle fetching
18167
18183
  * @param limit - Maximum number of candles to fetch
18168
18184
  * @returns Promise resolving to array of OHLCV candle data
18169
18185
  *
18170
18186
  * @example
18171
18187
  * ```typescript
18172
18188
  * const instance = new ExchangeInstance("binance");
18173
- * const candles = await instance.getCandles("BTCUSDT", "1m", new Date(), 100);
18189
+ * const candles = await instance.getCandles("BTCUSDT", "1m", 100);
18174
18190
  * ```
18175
18191
  */
18176
- this.getCandles = async (symbol, interval, since, limit) => {
18192
+ this.getCandles = async (symbol, interval, limit) => {
18177
18193
  backtest$1.loggerService.info(EXCHANGE_METHOD_NAME_GET_CANDLES, {
18178
18194
  exchangeName: this.exchangeName,
18179
18195
  symbol,
18180
18196
  interval,
18181
- since,
18182
18197
  limit,
18183
18198
  });
18184
- return await this._schema.getCandles(symbol, interval, since, limit);
18199
+ const step = INTERVAL_MINUTES[interval];
18200
+ const adjust = step * limit - step;
18201
+ if (!adjust) {
18202
+ throw new Error(`ExchangeInstance unknown time adjust for interval=${interval}`);
18203
+ }
18204
+ const when = new Date(Date.now());
18205
+ const since = new Date(when.getTime() - adjust * 60 * 1000);
18206
+ const data = await this._schema.getCandles(symbol, interval, since, limit);
18207
+ // Filter candles to strictly match the requested range
18208
+ const whenTimestamp = when.getTime();
18209
+ const sinceTimestamp = since.getTime();
18210
+ const filteredData = data.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
18211
+ if (filteredData.length < limit) {
18212
+ backtest$1.loggerService.warn(`ExchangeInstance Expected ${limit} candles, got ${filteredData.length}`);
18213
+ }
18214
+ return filteredData;
18215
+ };
18216
+ /**
18217
+ * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
18218
+ * The number of candles is configurable via GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT.
18219
+ *
18220
+ * Formula:
18221
+ * - Typical Price = (high + low + close) / 3
18222
+ * - VWAP = sum(typical_price * volume) / sum(volume)
18223
+ *
18224
+ * If volume is zero, returns simple average of close prices.
18225
+ *
18226
+ * @param symbol - Trading pair symbol
18227
+ * @returns Promise resolving to VWAP price
18228
+ * @throws Error if no candles available
18229
+ *
18230
+ * @example
18231
+ * ```typescript
18232
+ * const instance = new ExchangeInstance("binance");
18233
+ * const vwap = await instance.getAveragePrice("BTCUSDT");
18234
+ * console.log(vwap); // 50125.43
18235
+ * ```
18236
+ */
18237
+ this.getAveragePrice = async (symbol) => {
18238
+ backtest$1.loggerService.debug(`ExchangeInstance getAveragePrice`, {
18239
+ exchangeName: this.exchangeName,
18240
+ symbol,
18241
+ });
18242
+ const candles = await this.getCandles(symbol, "1m", GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT);
18243
+ if (candles.length === 0) {
18244
+ throw new Error(`ExchangeInstance getAveragePrice: no candles data for symbol=${symbol}`);
18245
+ }
18246
+ // VWAP (Volume Weighted Average Price)
18247
+ // Используем типичную цену (typical price) = (high + low + close) / 3
18248
+ const sumPriceVolume = candles.reduce((acc, candle) => {
18249
+ const typicalPrice = (candle.high + candle.low + candle.close) / 3;
18250
+ return acc + typicalPrice * candle.volume;
18251
+ }, 0);
18252
+ const totalVolume = candles.reduce((acc, candle) => acc + candle.volume, 0);
18253
+ if (totalVolume === 0) {
18254
+ // Если объем нулевой, возвращаем простое среднее close цен
18255
+ const sum = candles.reduce((acc, candle) => acc + candle.close, 0);
18256
+ return sum / candles.length;
18257
+ }
18258
+ const vwap = sumPriceVolume / totalVolume;
18259
+ return vwap;
18185
18260
  };
18186
18261
  /**
18187
18262
  * Format quantity according to exchange precision rules.
@@ -18240,7 +18315,10 @@ class ExchangeInstance {
18240
18315
  * ```typescript
18241
18316
  * import { Exchange } from "./classes/Exchange";
18242
18317
  *
18243
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
18318
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
18319
+ * exchangeName: "binance"
18320
+ * });
18321
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
18244
18322
  * exchangeName: "binance"
18245
18323
  * });
18246
18324
  * const formatted = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -18258,17 +18336,31 @@ class ExchangeUtils {
18258
18336
  /**
18259
18337
  * Fetch candles from data source (API or database).
18260
18338
  *
18339
+ * Automatically calculates the start date based on Date.now() and the requested interval/limit.
18340
+ * Uses the same logic as ClientExchange to ensure backwards compatibility.
18341
+ *
18261
18342
  * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
18262
18343
  * @param interval - Candle time interval (e.g., "1m", "1h")
18263
- * @param since - Start date for candle fetching
18264
18344
  * @param limit - Maximum number of candles to fetch
18265
18345
  * @param context - Execution context with exchange name
18266
18346
  * @returns Promise resolving to array of OHLCV candle data
18267
18347
  */
18268
- this.getCandles = async (symbol, interval, since, limit, context) => {
18348
+ this.getCandles = async (symbol, interval, limit, context) => {
18269
18349
  backtest$1.exchangeValidationService.validate(context.exchangeName, EXCHANGE_METHOD_NAME_GET_CANDLES);
18270
18350
  const instance = this._getInstance(context.exchangeName);
18271
- return await instance.getCandles(symbol, interval, since, limit);
18351
+ return await instance.getCandles(symbol, interval, limit);
18352
+ };
18353
+ /**
18354
+ * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
18355
+ *
18356
+ * @param symbol - Trading pair symbol
18357
+ * @param context - Execution context with exchange name
18358
+ * @returns Promise resolving to VWAP price
18359
+ */
18360
+ this.getAveragePrice = async (symbol, context) => {
18361
+ backtest$1.exchangeValidationService.validate(context.exchangeName, EXCHANGE_METHOD_NAME_GET_AVERAGE_PRICE);
18362
+ const instance = this._getInstance(context.exchangeName);
18363
+ return await instance.getAveragePrice(symbol);
18272
18364
  };
18273
18365
  /**
18274
18366
  * Format quantity according to exchange precision rules.
@@ -18306,7 +18398,10 @@ class ExchangeUtils {
18306
18398
  * import { Exchange } from "./classes/Exchange";
18307
18399
  *
18308
18400
  * // Using static-like API with context
18309
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
18401
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
18402
+ * exchangeName: "binance"
18403
+ * });
18404
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
18310
18405
  * exchangeName: "binance"
18311
18406
  * });
18312
18407
  * const qty = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -18318,7 +18413,8 @@ class ExchangeUtils {
18318
18413
  *
18319
18414
  * // Using instance API (no context needed, exchange set in constructor)
18320
18415
  * const binance = new ExchangeInstance("binance");
18321
- * const candles2 = await binance.getCandles("BTCUSDT", "1m", new Date(), 100);
18416
+ * const candles2 = await binance.getCandles("BTCUSDT", "1m", 100);
18417
+ * const vwap2 = await binance.getAveragePrice("BTCUSDT");
18322
18418
  * ```
18323
18419
  */
18324
18420
  const Exchange = new ExchangeUtils();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.5.30",
3
+ "version": "1.5.31",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -7720,7 +7720,10 @@ declare const Risk: RiskUtils;
7720
7720
  * ```typescript
7721
7721
  * import { Exchange } from "./classes/Exchange";
7722
7722
  *
7723
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
7723
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
7724
+ * exchangeName: "binance"
7725
+ * });
7726
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
7724
7727
  * exchangeName: "binance"
7725
7728
  * });
7726
7729
  * const formatted = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -7737,16 +7740,28 @@ declare class ExchangeUtils {
7737
7740
  /**
7738
7741
  * Fetch candles from data source (API or database).
7739
7742
  *
7743
+ * Automatically calculates the start date based on Date.now() and the requested interval/limit.
7744
+ * Uses the same logic as ClientExchange to ensure backwards compatibility.
7745
+ *
7740
7746
  * @param symbol - Trading pair symbol (e.g., "BTCUSDT")
7741
7747
  * @param interval - Candle time interval (e.g., "1m", "1h")
7742
- * @param since - Start date for candle fetching
7743
7748
  * @param limit - Maximum number of candles to fetch
7744
7749
  * @param context - Execution context with exchange name
7745
7750
  * @returns Promise resolving to array of OHLCV candle data
7746
7751
  */
7747
- getCandles: (symbol: string, interval: CandleInterval, since: Date, limit: number, context: {
7752
+ getCandles: (symbol: string, interval: CandleInterval, limit: number, context: {
7748
7753
  exchangeName: ExchangeName;
7749
7754
  }) => Promise<ICandleData[]>;
7755
+ /**
7756
+ * Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
7757
+ *
7758
+ * @param symbol - Trading pair symbol
7759
+ * @param context - Execution context with exchange name
7760
+ * @returns Promise resolving to VWAP price
7761
+ */
7762
+ getAveragePrice: (symbol: string, context: {
7763
+ exchangeName: ExchangeName;
7764
+ }) => Promise<number>;
7750
7765
  /**
7751
7766
  * Format quantity according to exchange precision rules.
7752
7767
  *
@@ -7778,7 +7793,10 @@ declare class ExchangeUtils {
7778
7793
  * import { Exchange } from "./classes/Exchange";
7779
7794
  *
7780
7795
  * // Using static-like API with context
7781
- * const candles = await Exchange.getCandles("BTCUSDT", "1m", new Date(), 100, {
7796
+ * const candles = await Exchange.getCandles("BTCUSDT", "1m", 100, {
7797
+ * exchangeName: "binance"
7798
+ * });
7799
+ * const vwap = await Exchange.getAveragePrice("BTCUSDT", {
7782
7800
  * exchangeName: "binance"
7783
7801
  * });
7784
7802
  * const qty = await Exchange.formatQuantity("BTCUSDT", 0.001, {
@@ -7790,7 +7808,8 @@ declare class ExchangeUtils {
7790
7808
  *
7791
7809
  * // Using instance API (no context needed, exchange set in constructor)
7792
7810
  * const binance = new ExchangeInstance("binance");
7793
- * const candles2 = await binance.getCandles("BTCUSDT", "1m", new Date(), 100);
7811
+ * const candles2 = await binance.getCandles("BTCUSDT", "1m", 100);
7812
+ * const vwap2 = await binance.getAveragePrice("BTCUSDT");
7794
7813
  * ```
7795
7814
  */
7796
7815
  declare const Exchange: ExchangeUtils;