UNPKG

crypto-backtest

Version:

Backtesting on market data imported from crypto exchange

87 lines 4.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Advisor = void 0; const IndicatorService_1 = require("./IndicatorService"); const StrategyExecuteData_1 = require("./StrategyExecuteData"); class Advisor { static async execute(candles, strategy) { const { indicatorInputs, warmup: strategyWarmup, execute } = strategy; const indicatorKeys = indicatorInputs.map((e) => e.key); // советник заработает только когда наберется необходимое количество вычисленных индикаторов для стратегии const warmup = strategyWarmup + indicatorInputs .map((e) => IndicatorService_1.IndicatorService.getStart(e.name, e.options)) .reduce((a, e) => Math.max(a, e)); return Promise.all(indicatorInputs.map((e) => IndicatorService_1.IndicatorService.execute({ candles, name: e.name, options: e.options, }))).then((results) => { // для каждой свечи попробовать найти вычисленный индикатор const data = candles.map((candle) => { const { time } = candle; const indicators = indicatorKeys.map((key, index) => { const indicator = results[index].find((e) => e.time === time); return { key, outputs: indicator ? indicator.values : [], }; }); const dataItem = new StrategyExecuteData_1.StrategyExecuteData({ time: candle.time, candle, indicators, }); return dataItem; }); const advices = []; for (let i = warmup; i < data.length; i++) { const side = execute(data.slice(i - warmup, i + 1)); advices.push({ time: data[i].time, side, }); } return Promise.resolve(advices); }); } static idealExecute(candles, fee) { const advices = []; const lastIndex = candles.length - 1; let min = candles[0]; let max = null; // max по времени всегда позднее open // max появляется только если current первысил порог fee // если current упал ниже max больше чем на fee, то пара фиксируется и начинается заново // порог = min * fee + max * fee + min candles.forEach((curr, i) => { if (curr.close > (min.close * (1 + fee)) / (1 - fee) && (!max || curr.close > max.close)) { // если рост и преодолен порог, то фиксируется новый пик max = curr; } if (max && (max.close > (curr.close * (1 + fee)) / (1 - fee) || i === lastIndex)) { // если падение ниже порога и после пика, то фиксируется пара advices.push({ time: min.time, side: "buy", }); advices.push({ time: max.time, side: "sell", }); min = curr; // считается новой впадиной max = null; // пик сбрасывается } if (!max && curr.close < min.close) { // если пика нет, и понижение, то фиксируется новая отметка впадина min = curr; } }); return advices; } } exports.Advisor = Advisor; //# sourceMappingURL=Advisor.js.map