UNPKG

quant-zero

Version:

Node-Quant is a powerful Node.js package for developing and testing quantitative trading strategies in cryptocurrency markets, offering tools for backtesting and performance analysis.

1,032 lines (991 loc) 30.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { ChartingSystem: () => ChartingSystem, CryptoPair: () => CryptoPair, DataSourceType: () => DataSourceType, Indicator: () => Indicator, Indicators: () => indicators_exports, Logger: () => Logger, NumberReturnType: () => NumberReturnType, OrderType: () => OrderType, PositionType: () => PositionType, ReportManager: () => ReportManager, Strategy: () => Strategy, TRADE_KEY: () => TRADE_KEY, TimeFrame: () => TimeFrame, TimelineEvents: () => TimelineEvents, Trade: () => Trade, TradeManager: () => TradeManager, logger: () => logger }); module.exports = __toCommonJS(index_exports); // src/lib/ChartingSystem.ts var ChartingSystem = class { transform(rawData) { return rawData; } }; // src/lib/Indicator.ts var import_events = require("events"); // src/types.ts var CryptoPair = /* @__PURE__ */ ((CryptoPair2) => { CryptoPair2["BTCUSDT"] = "BTC/USDT"; CryptoPair2["ETHUSDT"] = "ETH/USDT"; CryptoPair2["SOLUSDT"] = "SOL/USDT"; CryptoPair2["BNBUSDT"] = "BNB/USDT"; CryptoPair2["LTCUSDT"] = "LTC/USDT"; CryptoPair2["DOGEUSDT"] = "DOGE/USDT"; return CryptoPair2; })(CryptoPair || {}); var TimelineEvents = /* @__PURE__ */ ((TimelineEvents2) => { TimelineEvents2["PROVIDED"] = "provided"; TimelineEvents2["FED"] = "fed"; TimelineEvents2["GENERATED"] = "generated"; return TimelineEvents2; })(TimelineEvents || {}); var NumberReturnType = /* @__PURE__ */ ((NumberReturnType3) => { NumberReturnType3["RELATIVE"] = "relative"; NumberReturnType3["FIXED"] = "fixed"; return NumberReturnType3; })(NumberReturnType || {}); var OrderType = /* @__PURE__ */ ((OrderType2) => { OrderType2["MARKET"] = "market"; OrderType2["LIMIT"] = "limit"; OrderType2["STOP"] = "stop"; return OrderType2; })(OrderType || {}); var PositionType = /* @__PURE__ */ ((PositionType3) => { PositionType3["LONG"] = "long"; PositionType3["SHORT"] = "short"; return PositionType3; })(PositionType || {}); var TRADE_KEY = /* @__PURE__ */ ((TRADE_KEY2) => { TRADE_KEY2["ID"] = "id"; TRADE_KEY2["isOpen"] = "isOpen"; TRADE_KEY2["isClosed"] = "isClosed"; TRADE_KEY2["PL"] = "PL"; TRADE_KEY2["TP"] = "TP"; TRADE_KEY2["SL"] = "SL"; TRADE_KEY2["positionSize"] = "size"; TRADE_KEY2["leverage"] = "leverage"; TRADE_KEY2["drawdown"] = "drawdown"; TRADE_KEY2["openPrice"] = "openPrice"; TRADE_KEY2["closePrice"] = "closePrice"; TRADE_KEY2["fee"] = "fee"; TRADE_KEY2["pair"] = "pair"; TRADE_KEY2["blockChainTrack"] = "blockChainTrack"; TRADE_KEY2["orderType"] = "orderType"; TRADE_KEY2["positionType"] = "positionType"; TRADE_KEY2["timestamp"] = "timestamp"; return TRADE_KEY2; })(TRADE_KEY || {}); var DataSourceType = /* @__PURE__ */ ((DataSourceType2) => { DataSourceType2["PRICE"] = "price"; DataSourceType2["FACTOR"] = "factor"; return DataSourceType2; })(DataSourceType || {}); var TimeFrame = /* @__PURE__ */ ((TimeFrame2) => { TimeFrame2["SECOND"] = "1s"; TimeFrame2["MINUTE"] = "1m"; TimeFrame2["TWO_MINUTES"] = "2m"; TimeFrame2["THREE_MINUTES"] = "3m"; TimeFrame2["FIVE_MINUTES"] = "5m"; TimeFrame2["TEN_MINUTES"] = "10m"; TimeFrame2["FIFTEEN_MINUTES"] = "15m"; TimeFrame2["THIRTY_MINUTES"] = "30m"; TimeFrame2["FORTY_FIVE_MINUTES"] = "45m"; TimeFrame2["HOUR"] = "1h"; TimeFrame2["TWO_HOURS"] = "2h"; TimeFrame2["THREE_HOURS"] = "3h"; TimeFrame2["FOUR_HOURS"] = "4h"; TimeFrame2["DAY"] = "1d"; TimeFrame2["WEEK"] = "1w"; TimeFrame2["MONTH"] = "1M"; return TimeFrame2; })(TimeFrame || {}); // src/lib/Indicator.ts var Indicator = class extends import_events.EventEmitter { data = []; name; key; description; constructor({ name, key, description }) { super(); this.name = name; this.key = key; this.description = description; } // Provides the first sample of data if not already provided provide(data) { if (this.data.length === 0 && data.length > 0) { this.data = data; this.emit("provided" /* PROVIDED */, this.data); } } // Feeds new data in feed(data) { this.data.push(data); this.emit("fed" /* FED */, data); } // Generates the result generate() { return null; } clear() { this.data = []; } on(event, listener) { return super.on(event, listener); } }; // src/lib/Logger.ts var import_chalk = __toESM(require("chalk"), 1); var Logger = class { success(payload) { console.log(import_chalk.default.green(payload)); } debug(payload) { console.log(payload); } info(payload) { console.log(import_chalk.default.cyan(payload)); } warn(payload) { console.log(import_chalk.default.yellow(payload)); } error(payload) { console.log(import_chalk.default.red(payload)); } }; var logger = new Logger(); // src/lib/Strategy.ts var import_fs2 = __toESM(require("fs"), 1); var import_path2 = __toESM(require("path"), 1); // src/utils/dataInstaller.ts var import_fs = __toESM(require("fs"), 1); var import_path = __toESM(require("path"), 1); // src/exchange.ts var import_ccxt = __toESM(require("ccxt"), 1); var exchange = new import_ccxt.default.binance(); var exchange_default = exchange; // src/utils/dataInstaller.ts async function downloadPairData(pair, timeFrame, dataLength, dataFolderPath) { const fileName = `${pair.replace("/", "_")}_${dataLength}_${timeFrame}.json`; const filePath = import_path.default.join(dataFolderPath, fileName); if (import_fs.default.existsSync(filePath)) { console.log( `Data for ${pair} with length ${dataLength} already exists. Returning existing data.` ); const existingData = import_fs.default.readFileSync(filePath, "utf-8"); return { path: filePath, data: JSON.parse(existingData) }; } console.log(`Installing ${dataLength} candles for ${pair}.`); const fetchedData = await exchange_default.fetchOHLCV( pair, timeFrame, void 0, dataLength, { paginate: true } ); import_fs.default.writeFileSync(filePath, JSON.stringify(fetchedData, null, 2)); return { path: filePath, data: fetchedData }; } // src/utils/parseOHLCV.ts var parseIntoRows = (data) => { const timestamps = []; const opens = []; const highs = []; const lows = []; const closes = []; const volumes = []; data.forEach((candle) => { timestamps.push(candle[0]); opens.push(candle[1]); highs.push(candle[2]); lows.push(candle[3]); closes.push(candle[4]); volumes.push(candle[5]); }); return { timestamps, opens, highs, lows, closes, volumes }; }; // src/charting/CandleSticks.ts var CandleSticks = class extends ChartingSystem { transform(rawData) { const { opens, highs, lows, closes, timestamps, volumes } = parseIntoRows(rawData); return { open: opens, high: highs, low: lows, close: closes, timestamp: timestamps, volume: volumes }; } }; // src/charting/HeikenAishi.ts var import_technicalindicators = __toESM(require("technicalindicators"), 1); // src/charting/Renko.ts var import_technicalindicators2 = __toESM(require("technicalindicators"), 1); // src/utils/generateId.ts var import_crypto = __toESM(require("crypto"), 1); var generateMD5Id = () => { const seed = Math.random().toString(); return import_crypto.default.createHash("md5").update(seed).digest("hex"); }; // src/utils/maths/pl.ts function calcPL(currentClose, openPrice, positionType) { return positionType === "long" /* LONG */ ? 100 * ((currentClose - openPrice) / openPrice) : 100 * ((openPrice - currentClose) / openPrice); } // src/lib/Trade.ts var Trade = class { id; tradeData; constructor(options) { this.id = generateMD5Id(); this.tradeData = /* @__PURE__ */ new Map([ ["id" /* ID */, this.id], ["size" /* positionSize */, options.positionSize], ["leverage" /* leverage */, options.leverage], ["TP" /* TP */, options.TP], ["SL" /* SL */, options.SL], ["PL" /* PL */, 0], ["drawdown" /* drawdown */, 0], ["closePrice" /* closePrice */, void 0], ["openPrice" /* openPrice */, void 0], ["isClosed" /* isClosed */, false], ["fee" /* fee */, void 0], ["blockChainTrack" /* blockChainTrack */, void 0], ["timestamp" /* timestamp */, Date.now()], ["pair" /* pair */, options.pair], ["orderType" /* orderType */, options.orderType], ["positionType" /* positionType */, options.positionType], ["isOpen" /* isOpen */, options.open ?? false] ]); } open() { if (!this.tradeData.get("isClosed" /* isClosed */)) { this.tradeData.set("isOpen" /* isOpen */, true); } } close() { this.tradeData.set("isOpen" /* isOpen */, false); } updateTP(TP) { this.tradeData.set("TP" /* TP */, TP); } updateSL(SL) { this.tradeData.set("SL" /* SL */, SL); } getData() { return Object.fromEntries(this.tradeData); } onUpdate(update, updates) { if (this.tradeData.get("isClosed" /* isClosed */)) return; const currentClose = Number(update.at(4) ?? 0); if (!currentClose || currentClose === 0) return; const openPrice = this.tradeData.get("openPrice" /* openPrice */); const positionType = this.tradeData.get("positionType" /* positionType */); if (!openPrice) { this.tradeData.set("openPrice" /* openPrice */, currentClose); return; } const pl = calcPL(currentClose, openPrice, positionType); this.tradeData.set("PL" /* PL */, pl); this.tradeData.set("closePrice" /* closePrice */, currentClose); const currentDrawdown = this.tradeData.get("drawdown" /* drawdown */); if (pl < currentDrawdown) { this.tradeData.set("drawdown" /* drawdown */, pl); } } getFootprint() { } }; // src/managers/TradeManager.ts var TradeManager = class { trades = /* @__PURE__ */ new Map(); strategy; constructor(strategy) { this.strategy = strategy; } onUpdate(update, updates) { for (const trade of this.trades.values()) { if (!trade.getData()["isClosed" /* isClosed */]) { trade.onUpdate(update, updates); } } } getTrade(id) { return this.trades.get(id) || null; } getTrades() { return Array.from(this.trades.values()); } createTrade(options) { const trade = new Trade({ orderType: options.orderType, pair: this.strategy.strategyOptions.pair, positionSize: options.size, positionType: options.positionType, leverage: options.leverage ?? 1, open: options.open ?? false, SL: options.riskOptions?.SL, TP: options.riskOptions?.TP, isLive: false }); this.trades.set(trade.id, trade); return trade; } getTradeHistory() { const trades = this.getTrades(); return trades.filter(async (trade) => { const tradeData = await trade.getData(); return tradeData["isClosed" /* isClosed */]; }); } closeTrade(tradeId) { this.getTrade(tradeId)?.close(); } clear() { this.trades = /* @__PURE__ */ new Map(); } }; // src/utils/maths/alpha.ts function calcAlpha(r, rf = 0, beta, rm) { return r - rf - beta * (rm - rf); } // src/utils/maths/beta.ts function calcBeta(covariance, variance) { return covariance / variance; } // src/utils/maths/covariance.ts function calcCovariance(returns, marketReturn) { const meanReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length; return returns.reduce( (cov, r) => cov + (r - meanReturn) * (marketReturn - meanReturn), 0 ) / returns.length; } // src/utils/maths/sharpeE.ts function calcSharpeE(E, rp, rf = 0, sp) { return E * (rp - rf) / sp; } // src/utils/maths/variance.ts function calcVariance(returns) { const meanReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length; return returns.reduce((varSum, r) => varSum + Math.pow(r - meanReturn, 2), 0) / returns.length; } // src/utils/maths/standarddev.ts function calcStddev(returns) { return Math.sqrt(calcVariance(returns)); } // src/utils/getAvgMarketReturn.ts async function getAvgMarketReturn(pair, timeFrame, dataLength) { const data = await exchange_default.fetchOHLCV( pair, timeFrame, void 0, dataLength, { paginate: true } ); let totalReturn = 0; for (let i = 1; i < data.length; i++) { const prevCandle = data[i - 1]; const currCandle = data[i]; if (!prevCandle || !currCandle) continue; const prevClose = Number(prevCandle[4]); const currClose = Number(currCandle[4]); const returnPct = (currClose - prevClose) / prevClose * 100; totalReturn += returnPct; } return totalReturn / (data.length - 1); } // src/lib/Strategy.ts var Strategy = class { name; data = []; strategyOptions; tradeManager; indicators = /* @__PURE__ */ new Map(); pairDataPath = ""; constructor(strategyOptions) { const { name, dataLength = 100, timeFrame = "1m" /* MINUTE */, chartType = new CandleSticks(), indicators = [], simulationOptions, pair } = strategyOptions; this.name = strategyOptions.name; this.strategyOptions = { name, dataLength, timeFrame, chartType, indicators, simulationOptions: simulationOptions ?? { pair }, pair }; this.tradeManager = new TradeManager(this); } async loadData() { const { pair, timeFrame, dataLength } = this.strategyOptions; const dataFolderPath = import_path2.default.join(process.cwd(), "data"); if (!import_fs2.default.existsSync(dataFolderPath)) { import_fs2.default.mkdirSync(dataFolderPath); } const { path: pairDataPath, data } = await downloadPairData( pair, timeFrame, dataLength, dataFolderPath ); this.pairDataPath = pairDataPath; this.data = data; } provideAllIndicators() { this.strategyOptions.indicators.forEach( (indicator) => indicator.provide(this.data) ); } feedAllIndicators(data) { this.strategyOptions.indicators.forEach((indicator) => indicator.feed(data)); } async backtest({}) { const results = { alpha: 0, beta: 0, maxDrawdown: 0, maxProfit: 0, percentageProfitable: 0, return: 0, profitFactor: 0, sharpeE: 0, tradeCount: 0, reportData: { data: [], trades: [] } }; await Promise.all([this.internalStart(), this.onStart(this.data)]); for (const update of this.data) { await Promise.all([ this.internalUpdate(update, this.data), this.onUpdate(update, this.data) ]); } const tradeHistory = this.tradeManager.getTradeHistory(); results.tradeCount = tradeHistory.length; results.reportData.trades = tradeHistory; if (tradeHistory.length === 0) { return results; } const returns = tradeHistory.map((trade) => { const { ["PL" /* PL */]: pl = 0, ["leverage" /* leverage */]: leverage = 1 } = trade.getData(); return pl * leverage; }); const totalPL = returns.reduce((sum, r) => sum + r, 0); const profitableTrades = returns.filter((r) => r > 0); const lossTrades = returns.filter((r) => r < 0); results.return = totalPL; results.percentageProfitable = profitableTrades.length / returns.length * 100; results.maxDrawdown = Math.min(...returns); results.maxProfit = Math.max(...returns); const grossProfit = profitableTrades.reduce((sum, r) => sum + r, 0); const grossLoss = Math.abs(lossTrades.reduce((sum, r) => sum + r, 0)); results.profitFactor = grossLoss !== 0 ? grossProfit / grossLoss : grossProfit; const averageReturn = totalPL / returns.length; const riskFreeRate = 0; const marketReturn = await getAvgMarketReturn( this.strategyOptions.pair, "1M" /* MONTH */, 60 // 5 years * 12 months ); const covariance = calcCovariance(returns, marketReturn) || 0; const variance = calcVariance(returns) || 0; const standardDeviation = calcStddev(returns); results.beta = calcBeta(covariance, variance); results.alpha = calcAlpha( averageReturn, riskFreeRate, results.beta, marketReturn ); results.sharpeE = calcSharpeE( averageReturn, results.return, riskFreeRate, standardDeviation ); results.reportData.data.push({ name: `${this.strategyOptions.pair.replaceAll("/", "_")}_${this.strategyOptions.timeFrame}`, type: "price" /* PRICE */, data: this.data }); this.indicators.forEach((indicatorData, indicatorKey) => { results.reportData.data.push({ name: indicatorKey, type: "factor" /* FACTOR */, data: indicatorData }); }); return results; } internalStart() { this.strategyOptions.indicators.forEach((indicator) => { indicator.clear(); }); } async internalUpdate(update, updates) { this.feedAllIndicators(update); await Promise.all( this.strategyOptions.indicators.map(async (indicator) => { this.indicators.set(indicator.key, await indicator.generate()); }) ); this.tradeManager.onUpdate(update, updates); } live() { } onStart(updates) { } onUpdate(update, updates) { } }; // src/managers/Report/ReportManager.ts var import_express = __toESM(require("express"), 1); var import_path3 = __toESM(require("path"), 1); var import_meta = {}; var ReportManager = class { app = (0, import_express.default)(); PORT = 2555; viewsPath; constructor() { this.viewsPath = new URL("./", import_meta.url).pathname; this.initializeApp(); } initializeApp() { this.app.use(import_express.default.json()); this.app.set("views", this.viewsPath); this.app.use(import_express.default.static(this.viewsPath)); this.app.listen(this.PORT, () => { console.log(`Report server listening on port ${this.PORT}`); }); } generateReport(strategy, reportData) { const reportId = generateMD5Id(); const { trades, data } = reportData; const reportRouter = import_express.default.Router(); const priceData = data.filter((e) => e.type === "price" /* PRICE */); const factorData = data.filter((e) => e.type === "factor" /* FACTOR */); reportRouter.get("/price-data", (_, res) => { res.json(priceData); }); reportRouter.get("/factor-data", (_, res) => { res.json(factorData); }); reportRouter.get("/trade-data", (_, res) => { res.json(trades); }); reportRouter.get("/", (_, res) => { const buildPath = import_path3.default.join(this.viewsPath, "performance/dist/index.html").replace("\\C", "C"); res.sendFile(buildPath); }); this.app.use(`/${reportId}`, reportRouter); console.log( `Report for ${strategy.name}: http://localhost:${this.PORT}/${reportId}` ); } }; // src/indicators/index.ts var indicators_exports = {}; __export(indicators_exports, { ADX: () => ADX, ATR: () => ATR, BB: () => BB, EMA: () => EMA, ForceIndex: () => ForceIndex, IchimokuCloud: () => IchimokuCloud, MACD: () => MACD, RSI: () => RSI, SMA: () => SMA, StockRSI: () => StockRSI, VWAP: () => VWAP, VolumeProfile: () => VolumeProfile, WEMA: () => WEMA }); // src/indicators/EMA.ts var import_technicalindicators3 = __toESM(require("technicalindicators"), 1); var EMA = class extends Indicator { period = 9; constructor(key, options) { super({ name: "EMA", key, description: "Exponential Moving Average." }); if (options.period) this.period = options.period; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const ema = import_technicalindicators3.default.EMA.calculate({ period: this.period, values }); return ema; } }; // src/indicators/SMA.ts var import_technicalindicators4 = __toESM(require("technicalindicators"), 1); var SMA = class extends Indicator { period = 9; constructor(key, options) { super({ name: "SMA", key, description: "Simple Moving Average." }); if (options.period) this.period = options.period; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const sma = import_technicalindicators4.default.SMA.calculate({ period: this.period, values }); return sma; } }; // src/indicators/ATR.ts var import_technicalindicators5 = __toESM(require("technicalindicators"), 1); var ATR = class extends Indicator { period = 14; constructor(key, options) { super({ name: "ATR", key, description: "Average True Range." }); if (options.period) this.period = options.period; } generate() { const { highs, lows, closes } = parseIntoRows(this.data); const atr = import_technicalindicators5.default.ATR.calculate({ period: this.period, high: highs, low: lows, close: closes }); return atr; } }; // src/indicators/RSI.ts var import_technicalindicators6 = __toESM(require("technicalindicators"), 1); var RSI = class extends Indicator { period = 14; constructor(key, options) { super({ name: "RSI", key, description: "Relative Strength Index." }); if (options.period) this.period = options.period; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const rsi = import_technicalindicators6.default.RSI.calculate({ period: this.period, values }); return rsi; } }; // src/indicators/MACD.ts var import_technicalindicators7 = __toESM(require("technicalindicators"), 1); var MACD = class extends Indicator { fastPeriod = 12; slowPeriod = 26; signalSmoothing = 9; MAType = "SMA"; MAOscillatorType = "SMA"; constructor(key, options) { super({ name: "MACD", key, description: "Moving Average Convergence/Divergence." }); if (options.fastPeriod) this.fastPeriod = options.fastPeriod; if (options.slowPeriod) this.slowPeriod = options.slowPeriod; if (options.signalSmoothing) this.signalSmoothing = options.signalSmoothing; if (options.MAOscillatorType) this.MAOscillatorType = options.MAOscillatorType; if (options.MAType) this.MAType = options.MAType; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const macd = import_technicalindicators7.default.MACD.calculate({ fastPeriod: this.fastPeriod, slowPeriod: this.slowPeriod, SimpleMAOscillator: this.MAOscillatorType === "SMA" ? true : false, SimpleMASignal: this.MAType === "SMA" ? true : false, signalPeriod: this.signalSmoothing, values }); return macd; } }; // src/indicators/StochRSI.ts var import_technicalindicators8 = __toESM(require("technicalindicators"), 1); var StockRSI = class extends Indicator { dPeriod = 9; kPeriod = 12; rsiPeriod = 14; stochasticPeriod = 16; constructor(key, options) { super({ name: "Bollinger Bands", key, description: "Boillinger Bands." }); if (options.dPeriod) this.dPeriod = options.dPeriod; if (options.kPeriod) this.kPeriod = options.kPeriod; if (options.rsiPeriod) this.rsiPeriod = options.rsiPeriod; if (options.stochasticPeriod) this.stochasticPeriod = options.stochasticPeriod; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const stochRSI = import_technicalindicators8.default.StochasticRSI.calculate({ values, dPeriod: this.dPeriod, kPeriod: this.kPeriod, rsiPeriod: this.rsiPeriod, stochasticPeriod: this.stochasticPeriod }); return stochRSI; } }; // src/indicators/BB.ts var import_technicalindicators9 = __toESM(require("technicalindicators"), 1); var BB = class extends Indicator { period = 9; stdDev = 1; constructor(key, options) { super({ name: "Bollinger Bands", key, description: "Boillinger Bands." }); if (options.period) this.period = options.period; if (options.stdDev) this.stdDev = options.stdDev; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const bb = import_technicalindicators9.default.BollingerBands.calculate({ values, period: this.period, stdDev: this.stdDev }); return bb; } }; // src/indicators/IchimokuCloud.ts var import_technicalindicators10 = __toESM(require("technicalindicators"), 1); var IchimokuCloud = class extends Indicator { basePeriod = 9; conversionPeriod = 12; spanPeriod = 16; displacement = 21; constructor(key, options) { super({ name: "Ichimoku Cloud", key, description: "Ichimoku Cloud." }); if (options.basePeriod) this.basePeriod = options.basePeriod; if (options.conversionPeriod) this.conversionPeriod = options.conversionPeriod; if (options.spanPeriod) this.spanPeriod = options.spanPeriod; if (options.displacement) this.displacement = options.displacement; } generate() { const { highs, lows } = parseIntoRows(this.data); const ichimoku = import_technicalindicators10.default.IchimokuCloud.calculate({ basePeriod: this.basePeriod, conversionPeriod: this.conversionPeriod, spanPeriod: this.spanPeriod, displacement: this.displacement, high: highs, low: lows }); return ichimoku; } }; // src/indicators/WEMA.ts var import_technicalindicators11 = __toESM(require("technicalindicators"), 1); var WEMA = class extends Indicator { period = 9; constructor(key, options) { super({ name: "Weighted Exponential Moving Average", key, description: "Weighted Exponential Moving Average." }); if (options.period) this.period = options.period; } generate() { const values = this.data.map((update) => update[4]).filter((value) => value !== void 0); const wema = import_technicalindicators11.default.WEMA.calculate({ period: this.period, values }); return wema; } }; // src/indicators/ADX.ts var import_technicalindicators12 = __toESM(require("technicalindicators"), 1); var ADX = class extends Indicator { period = 9; constructor(key, options) { super({ name: "ADX", key, description: "Trend Strength." }); if (options.period) this.period = options.period; } generate() { const { closes, highs, lows } = parseIntoRows(this.data); const adx = import_technicalindicators12.default.ADX.calculate({ period: this.period, close: closes, high: highs, low: lows }); return adx; } }; // src/indicators/VolumeProfile.ts var import_technicalindicators13 = __toESM(require("technicalindicators"), 1); var VolumeProfile = class extends Indicator { numberOfBars = 20; constructor(key, options) { super({ name: "Volume Profile", key, description: "Volume Profile." }); if (options.numberOfBars) this.numberOfBars = options.numberOfBars; } generate() { const { closes, highs, lows, opens, volumes } = parseIntoRows(this.data); const volumeProfile = import_technicalindicators13.default.VolumeProfile.calculate({ close: closes, high: highs, low: lows, open: opens, volume: volumes, noOfBars: this.numberOfBars }); return volumeProfile; } }; // src/indicators/VWAP.ts var import_technicalindicators14 = __toESM(require("technicalindicators"), 1); var VWAP = class extends Indicator { constructor(key) { super({ name: "VWAP", key, description: "Volume-weighted Average Price." }); } generate() { const { closes, highs, lows, opens, timestamps, volumes } = parseIntoRows( this.data ); const vwap = import_technicalindicators14.default.VWAP.calculate({ close: closes, high: highs, low: lows, volume: volumes }); return vwap; } }; // src/indicators/ForceIndex.ts var import_technicalindicators15 = __toESM(require("technicalindicators"), 1); var ForceIndex = class extends Indicator { period = 9; constructor(key, options) { super({ name: "ForceIndex", key, description: "Force Index." }); if (options.period) this.period = options.period; } generate() { const { closes, volumes } = parseIntoRows(this.data); const forceIndex = import_technicalindicators15.default.ForceIndex.calculate({ period: this.period, close: closes, volume: volumes }); return forceIndex; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ChartingSystem, CryptoPair, DataSourceType, Indicator, Indicators, Logger, NumberReturnType, OrderType, PositionType, ReportManager, Strategy, TRADE_KEY, TimeFrame, TimelineEvents, Trade, TradeManager, logger }); //# sourceMappingURL=index.cjs.map