opentrader
Version:
OpenTrader is a powerful open-source crypto trading bot designated to automate your trading strategies on various cryptocurrency exchanges.
1,747 lines (1,690 loc) • 57.9 kB
JavaScript
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
if (typeof globalThis.__dirname === "undefined") {
globalThis.__dirname = new URL('.', import.meta.url).pathname;
}
if (typeof globalThis.__filename === "undefined") {
globalThis.__filename = new URL(import.meta.url).pathname;
}
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 __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __commonJS = (cb, mod) => function __require2() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
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
));
// ../../packages/bot-processor/src/effects/types/effect-types.ts
var USE_SMART_TRADE = "USE_SMART_TRADE";
var USE_TRADE = "USE_TRADE";
var USE_ARB_TRADE = "USE_ARB_TRADE";
var USE_DCA = "USE_DCA";
var BUY = "BUY";
var SELL = "SELL";
var REPLACE_SMART_TRADE = "REPLACE_SMART_TRADE";
var GET_SMART_TRADE = "GET_SMART_TRADE";
var CREATE_SMART_TRADE = "CREATE_SMART_TRADE";
var CANCEL_SMART_TRADE = "CANCEL_SMART_TRADE";
var USE_EXCHANGE = "USE_EXCHANGE";
var USE_INDICATOR = "USE_INDICATOR";
var USE_INDICATORS = "USE_INDICATORS";
var USE_MARKET = "USE_MARKET";
var USE_CANDLE = "USE_CANDLE";
var USE_RSI_INDICATOR = "USE_RSI_INDICATOR";
// ../../packages/bot-processor/src/effects/utils/index.ts
var makeEffect = (type, payload, ref) => {
return {
ref,
type,
payload
};
};
function isEffect(effect) {
return !!effect?.type;
}
// ../../packages/bot-processor/src/effects/smart-trade.ts
var DEFAULT_REF = "0";
function useSmartTrade(params, ref = DEFAULT_REF) {
return makeEffect(USE_SMART_TRADE, params, ref);
}
function getSmartTrade(ref = DEFAULT_REF) {
return makeEffect(GET_SMART_TRADE, void 0, ref);
}
function createSmartTrade(payload, ref = DEFAULT_REF) {
return makeEffect(CREATE_SMART_TRADE, payload, ref);
}
function cancelSmartTrade(ref = DEFAULT_REF) {
return makeEffect(CANCEL_SMART_TRADE, void 0, ref);
}
function replaceSmartTrade(payload, ref = DEFAULT_REF) {
return makeEffect(REPLACE_SMART_TRADE, payload, ref);
}
// ../../packages/bot-processor/src/effects/buy.ts
function buy(payload, ref = "0") {
return makeEffect(BUY, payload, ref);
}
// ../../packages/bot-processor/src/effects/sell.ts
function sell(payload, ref = "0") {
return makeEffect(SELL, payload, ref);
}
// ../../packages/bot-processor/src/effects/useExchange.ts
function useExchange(label) {
return makeEffect(USE_EXCHANGE, label, void 0);
}
// ../../packages/bot-processor/src/effects/useIndicators.ts
function useIndicator(...[name, barSize, options]) {
return makeEffect(USE_INDICATOR, { name, barSize, options }, void 0);
}
function useIndicators(payload) {
return makeEffect(USE_INDICATORS, payload, void 0);
}
// ../../packages/bot-processor/src/effects/useTrade.ts
function useTrade(params, ref = "0") {
return makeEffect(USE_TRADE, params, ref);
}
// ../../packages/bot-processor/src/effects/useArbTrade.ts
function useArbTrade(params, ref = "0") {
return makeEffect(USE_ARB_TRADE, params, ref);
}
// ../../packages/bot-processor/src/effects/useDca.ts
function useDca(params, ref = "0") {
return makeEffect(USE_DCA, params, ref);
}
// ../../packages/bot-processor/src/effects/market.ts
function useMarket() {
return makeEffect(USE_MARKET, void 0, void 0);
}
function useCandle(index = -1) {
return makeEffect(USE_CANDLE, index, void 0);
}
// ../../packages/bot-processor/src/effects/indicators.ts
function useRSI(periods = 14) {
return makeEffect(USE_RSI_INDICATOR, periods, void 0);
}
// ../../packages/bot-processor/src/types/bot/bot-template.type.ts
var Watcher = {
watchTrades: "watchTrades",
watchOrderbook: "watchOrderbook",
watchTicker: "watchTicker",
watchCandles: "watchCandles"
};
// ../../packages/types/src/common/db.enums.ts
var XOrderSide = {
Buy: "Buy",
Sell: "Sell"
};
var XOrderStatus = {
Idle: "Idle",
Placed: "Placed",
Filled: "Filled",
Canceled: "Canceled",
Revoked: "Revoked",
Deleted: "Deleted"
};
var XOrderType = {
Limit: "Limit",
Market: "Market"
};
var XSmartTradeType = {
Trade: "Trade",
DCA: "DCA",
ARB: "ARB"
};
var XEntryType = {
Order: "Order",
Ladder: "Ladder"
};
var XTakeProfitType = {
Order: "Order",
Ladder: "Ladder",
None: "None"
};
var XEntityType = {
EntryOrder: "EntryOrder",
TakeProfitOrder: "TakeProfitOrder",
StopLossOrder: "StopLossOrder",
SafetyOrder: "SafetyOrder"
};
// ../../packages/types/src/common/enums.ts
var BarSize = {
ONE_MINUTE: "1m",
FIVE_MINUTES: "5m",
FIFTEEN_MINUTES: "15m",
ONE_HOUR: "1h",
FOUR_HOURS: "4h",
ONE_DAY: "1d",
ONE_WEEK: "1w",
ONE_MONTH: "1M",
THREE_MONTHS: "3M"
};
var ExchangeCode = {
OKX: "OKX",
BYBIT: "BYBIT",
BINANCE: "BINANCE",
KRAKEN: "KRAKEN",
COINBASE: "COINBASE",
GATEIO: "GATEIO",
BITGET: "BITGET"
};
// ../../packages/types/src/smart-trade/enums.ts
var OrderType = {
Limit: "Limit",
Market: "Market"
};
// ../../packages/types/src/indicators/indicator-value.ts
var isIndicatorValue = (value) => {
return value?.indicatorValue !== void 0 && value?.periods !== void 0 && value?.timeframe !== void 0;
};
// ../../packages/types/src/strategy-runner/context.ts
var StrategyAction = {
start: "start",
stop: "stop",
process: "process"
};
var MarketEventType = {
onOrderFilled: "onOrderFilled",
onTradeCompleted: "onTradeCompleted",
onCandleClosed: "onCandleClosed",
onPublicTrade: "onPublicTrade",
onOrderbookChange: "onOrderbookChange",
onTickerChange: "onTickerChange"
};
// ../../packages/bot-processor/src/types/smart-trade/smart-trade.service.ts
var SmartTradeService = class {
constructor(ref, smartTrade) {
this.ref = ref;
this.smartTrade = smartTrade;
this.type = smartTrade.type;
this.entry = smartTrade.entryOrder;
this.tp = smartTrade.tpOrder;
this.sl = smartTrade.slOrder;
}
type;
entry;
tp;
sl;
/**
* Create a new SmartTrade with same buy/sell orders
*/
replace() {
return replaceSmartTrade(this.smartTrade, this.ref);
}
cancel() {
return cancelSmartTrade(this.ref);
}
isCompleted() {
const closedWithTakeProfit = this.smartTrade.entryOrder.status === XOrderStatus.Filled && this.smartTrade.tpOrder?.status === XOrderStatus.Filled;
const closedWithStopLoss = this.smartTrade.entryOrder.status === XOrderStatus.Filled && this.smartTrade.slOrder?.status === XOrderStatus.Filled;
return closedWithTakeProfit || closedWithStopLoss;
}
};
// ../../packages/bot-processor/src/bot-control.ts
var BotControl = class {
constructor(store, bot) {
this.store = store;
this.bot = bot;
}
async stop() {
return this.store.stopBot(this.bot.id);
}
async getSmartTrade(ref) {
return this.store.getSmartTrade(ref, this.bot.id);
}
async createSmartTrade(ref, payload) {
return this.store.createSmartTrade(ref, payload, this.bot.id);
}
async updateSmartTrade(ref, payload) {
return this.store.updateSmartTrade(ref, payload, this.bot.id);
}
async getOrCreateSmartTrade(ref, payload) {
const smartTrade = await this.store.getSmartTrade(ref, this.bot.id);
if (smartTrade) {
return smartTrade;
}
return this.store.createSmartTrade(ref, payload, this.bot.id);
}
async replaceSmartTrade(ref, smartTrade) {
const copyOrder = (order) => ({
type: order.type,
side: order.side,
quantity: order.quantity,
price: order.price,
relativePrice: order.relativePrice,
stopPrice: order.stopPrice
});
const entry = copyOrder(smartTrade.entryOrder);
switch (smartTrade.type) {
case "Trade":
return this.store.createSmartTrade(
ref,
{ type: "Trade", entry, tp: smartTrade.tpOrder ? copyOrder(smartTrade.tpOrder) : void 0 },
this.bot.id
);
case "DCA":
return this.store.createSmartTrade(
ref,
{
type: "DCA",
entry,
tp: copyOrder(smartTrade.tpOrder),
safetyOrders: smartTrade.safetyOrders.map(copyOrder)
},
this.bot.id
);
case "ARB":
return this.store.createSmartTrade(
ref,
{
type: "ARB",
entry,
tp: copyOrder(smartTrade.tpOrder)
},
this.bot.id
);
}
}
async cancelSmartTrade(ref) {
return this.store.cancelSmartTrade(ref, this.bot.id);
}
async getExchange(label) {
return this.store.getExchange(label);
}
};
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/Utils/LinkedList.js
var Item = class {
constructor(data, prev, next) {
this.next = next;
if (next)
next.prev = this;
this.prev = prev;
if (prev)
prev.next = this;
this.data = data;
}
};
var LinkedList = class {
constructor() {
this._length = 0;
}
get head() {
return this._head && this._head.data;
}
get tail() {
return this._tail && this._tail.data;
}
get current() {
return this._current && this._current.data;
}
get length() {
return this._length;
}
push(data) {
this._tail = new Item(data, this._tail);
if (this._length === 0) {
this._head = this._tail;
this._current = this._head;
this._next = this._head;
}
this._length++;
}
pop() {
var tail = this._tail;
if (this._length === 0) {
return;
}
this._length--;
if (this._length === 0) {
this._head = this._tail = this._current = this._next = void 0;
return tail.data;
}
this._tail = tail.prev;
this._tail.next = void 0;
if (this._current === tail) {
this._current = this._tail;
this._next = void 0;
}
return tail.data;
}
shift() {
var head = this._head;
if (this._length === 0) {
return;
}
this._length--;
if (this._length === 0) {
this._head = this._tail = this._current = this._next = void 0;
return head.data;
}
this._head = this._head.next;
if (this._current === head) {
this._current = this._head;
this._next = this._current.next;
}
return head.data;
}
unshift(data) {
this._head = new Item(data, void 0, this._head);
if (this._length === 0) {
this._tail = this._head;
this._next = this._head;
}
this._length++;
}
unshiftCurrent() {
var current = this._current;
if (current === this._head || this._length < 2) {
return current && current.data;
}
if (current === this._tail) {
this._tail = current.prev;
this._tail.next = void 0;
this._current = this._tail;
} else {
current.next.prev = current.prev;
current.prev.next = current.next;
this._current = current.prev;
}
this._next = this._current.next;
current.next = this._head;
current.prev = void 0;
this._head.prev = current;
this._head = current;
return current.data;
}
removeCurrent() {
var current = this._current;
if (this._length === 0) {
return;
}
this._length--;
if (this._length === 0) {
this._head = this._tail = this._current = this._next = void 0;
return current.data;
}
if (current === this._tail) {
this._tail = current.prev;
this._tail.next = void 0;
this._current = this._tail;
} else if (current === this._head) {
this._head = current.next;
this._head.prev = void 0;
this._current = this._head;
} else {
current.next.prev = current.prev;
current.prev.next = current.next;
this._current = current.prev;
}
this._next = this._current.next;
return current.data;
}
resetCursor() {
this._current = this._next = this._head;
return this;
}
next() {
var next = this._next;
if (next !== void 0) {
this._next = next.next;
this._current = next;
return next.data;
}
}
};
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/config.js
var config = {};
function getConfig(key) {
return config[key];
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/Utils/NumberFormatter.js
function format(v) {
let precision = getConfig("precision");
if (precision) {
return parseFloat(v.toPrecision(precision));
}
return v;
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/indicator/indicator.js
var Indicator = class {
constructor(input) {
this.format = input.format || format;
}
static reverseInputs(input) {
if (input.reversedInput) {
input.values ? input.values.reverse() : void 0;
input.open ? input.open.reverse() : void 0;
input.high ? input.high.reverse() : void 0;
input.low ? input.low.reverse() : void 0;
input.close ? input.close.reverse() : void 0;
input.volume ? input.volume.reverse() : void 0;
input.timestamp ? input.timestamp.reverse() : void 0;
}
}
getResult() {
return this.result;
}
};
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/moving_averages/SMA.js
var SMA = class extends Indicator {
constructor(input) {
super(input);
this.period = input.period;
this.price = input.values;
var genFn = function* (period) {
var list = new LinkedList();
var sum = 0;
var counter = 1;
var current = yield;
var result;
list.push(0);
while (true) {
if (counter < period) {
counter++;
list.push(current);
sum = sum + current;
} else {
sum = sum - list.shift() + current;
result = sum / period;
list.push(current);
}
current = yield result;
}
};
this.generator = genFn(this.period);
this.generator.next();
this.result = [];
this.price.forEach((tick) => {
var result = this.generator.next(tick);
if (result.value !== void 0) {
this.result.push(this.format(result.value));
}
});
}
nextValue(price) {
var result = this.generator.next(price).value;
if (result != void 0)
return this.format(result);
}
};
SMA.calculate = sma;
function sma(input) {
Indicator.reverseInputs(input);
var result = new SMA(input).result;
if (input.reversedInput) {
result.reverse();
}
Indicator.reverseInputs(input);
return result;
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/moving_averages/EMA.js
var EMA = class extends Indicator {
constructor(input) {
super(input);
var period = input.period;
var priceArray = input.values;
var exponent = 2 / (period + 1);
var sma3;
this.result = [];
sma3 = new SMA({ period, values: [] });
var genFn = function* () {
var tick = yield;
var prevEma;
while (true) {
if (prevEma !== void 0 && tick !== void 0) {
prevEma = (tick - prevEma) * exponent + prevEma;
tick = yield prevEma;
} else {
tick = yield;
prevEma = sma3.nextValue(tick);
if (prevEma)
tick = yield prevEma;
}
}
};
this.generator = genFn();
this.generator.next();
this.generator.next();
priceArray.forEach((tick) => {
var result = this.generator.next(tick);
if (result.value != void 0) {
this.result.push(this.format(result.value));
}
});
}
nextValue(price) {
var result = this.generator.next(price).value;
if (result != void 0)
return this.format(result);
}
};
EMA.calculate = ema;
function ema(input) {
Indicator.reverseInputs(input);
var result = new EMA(input).result;
if (input.reversedInput) {
result.reverse();
}
Indicator.reverseInputs(input);
return result;
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/Utils/AverageGain.js
var AverageGain = class extends Indicator {
constructor(input) {
super(input);
let values = input.values;
let period = input.period;
let format2 = this.format;
this.generator = function* (period2) {
var currentValue = yield;
var counter = 1;
var gainSum = 0;
var avgGain;
var gain;
var lastValue = currentValue;
currentValue = yield;
while (true) {
gain = currentValue - lastValue;
gain = gain > 0 ? gain : 0;
if (gain > 0) {
gainSum = gainSum + gain;
}
if (counter < period2) {
counter++;
} else if (avgGain === void 0) {
avgGain = gainSum / period2;
} else {
avgGain = (avgGain * (period2 - 1) + gain) / period2;
}
lastValue = currentValue;
avgGain = avgGain !== void 0 ? format2(avgGain) : void 0;
currentValue = yield avgGain;
}
}(period);
this.generator.next();
this.result = [];
values.forEach((tick) => {
var result = this.generator.next(tick);
if (result.value !== void 0) {
this.result.push(result.value);
}
});
}
nextValue(price) {
return this.generator.next(price).value;
}
};
AverageGain.calculate = averagegain;
function averagegain(input) {
Indicator.reverseInputs(input);
var result = new AverageGain(input).result;
if (input.reversedInput) {
result.reverse();
}
Indicator.reverseInputs(input);
return result;
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/Utils/AverageLoss.js
var AverageLoss = class extends Indicator {
constructor(input) {
super(input);
let values = input.values;
let period = input.period;
let format2 = this.format;
this.generator = function* (period2) {
var currentValue = yield;
var counter = 1;
var lossSum = 0;
var avgLoss;
var loss;
var lastValue = currentValue;
currentValue = yield;
while (true) {
loss = lastValue - currentValue;
loss = loss > 0 ? loss : 0;
if (loss > 0) {
lossSum = lossSum + loss;
}
if (counter < period2) {
counter++;
} else if (avgLoss === void 0) {
avgLoss = lossSum / period2;
} else {
avgLoss = (avgLoss * (period2 - 1) + loss) / period2;
}
lastValue = currentValue;
avgLoss = avgLoss !== void 0 ? format2(avgLoss) : void 0;
currentValue = yield avgLoss;
}
}(period);
this.generator.next();
this.result = [];
values.forEach((tick) => {
var result = this.generator.next(tick);
if (result.value !== void 0) {
this.result.push(result.value);
}
});
}
nextValue(price) {
return this.generator.next(price).value;
}
};
AverageLoss.calculate = averageloss;
function averageloss(input) {
Indicator.reverseInputs(input);
var result = new AverageLoss(input).result;
if (input.reversedInput) {
result.reverse();
}
Indicator.reverseInputs(input);
return result;
}
// ../../node_modules/.pnpm/technicalindicators@3.1.0/node_modules/technicalindicators/lib/oscillators/RSI.js
var RSI = class extends Indicator {
constructor(input) {
super(input);
var period = input.period;
var values = input.values;
var GainProvider = new AverageGain({ period, values: [] });
var LossProvider = new AverageLoss({ period, values: [] });
this.generator = function* (period2) {
var current = yield;
var lastAvgGain, lastAvgLoss, RS, currentRSI;
while (true) {
lastAvgGain = GainProvider.nextValue(current);
lastAvgLoss = LossProvider.nextValue(current);
if (lastAvgGain !== void 0 && lastAvgLoss !== void 0) {
if (lastAvgLoss === 0) {
currentRSI = 100;
} else if (lastAvgGain === 0) {
currentRSI = 0;
} else {
RS = lastAvgGain / lastAvgLoss;
RS = isNaN(RS) ? 0 : RS;
currentRSI = parseFloat((100 - 100 / (1 + RS)).toFixed(2));
}
}
current = yield currentRSI;
}
}();
this.generator.next();
this.result = [];
values.forEach((tick) => {
var result = this.generator.next(tick);
if (result.value !== void 0) {
this.result.push(result.value);
}
});
}
nextValue(price) {
return this.generator.next(price).value;
}
};
RSI.calculate = rsi;
function rsi(input) {
Indicator.reverseInputs(input);
var result = new RSI(input).result;
if (input.reversedInput) {
result.reverse();
}
Indicator.reverseInputs(input);
return result;
}
// ../../packages/indicators/src/utils/indicator.error.ts
var IndicatorError = class extends Error {
indicator;
/**
* @param message - Error message
* @param indicator - Indicator name, e.g. "RSI"
*/
constructor(message, indicator) {
super(message);
this.name = "IndicatorError";
this.indicator = indicator;
}
};
// ../../packages/indicators/src/indicators/rsi.ts
async function rsi2(params, candles) {
const prices = candles.map((candle) => candle.close);
if (params.periods < 2) {
throw new IndicatorError("RSI requires at least 2 periods", "RSI");
}
if (candles.length < 1) {
throw new IndicatorError("No candles provided for RSI", "RSI");
}
const rsiValues = RSI.calculate({
period: params.periods,
values: prices
});
const emptyRsiValues = new Array(
candles.length - rsiValues.length
).fill(NaN);
return [...emptyRsiValues, ...rsiValues];
}
// ../../packages/indicators/src/indicators/ema.ts
async function ema2(params, candles) {
const prices = candles.map((candle) => candle.close);
if (params.periods < 2) {
throw new IndicatorError("EMA requires at least 2 periods", "EMA");
}
if (candles.length < 1) {
throw new IndicatorError("No candles provided for EMA", "EMA");
}
const indicatorValues = EMA.calculate({
period: params.periods,
values: prices
});
const emptyIndicatorValue = new Array(
candles.length - indicatorValues.length
).fill(NaN);
return [...emptyIndicatorValue, ...indicatorValues];
}
// ../../packages/indicators/src/indicators/sma.ts
async function sma2(params, candles) {
const prices = candles.map((candle) => candle.close);
if (params.periods < 2) {
throw new IndicatorError("SMA requires at least 2 periods", "SMA");
}
if (candles.length < 1) {
throw new IndicatorError("No candles provided for SMA", "SMA");
}
const indicatorValues = SMA.calculate({
period: params.periods,
values: prices
});
const emptyIndicatorValue = new Array(
candles.length - indicatorValues.length
).fill(NaN);
return [...emptyIndicatorValue, ...indicatorValues];
}
// ../../node_modules/.pnpm/big.js@6.2.2/node_modules/big.js/big.mjs
var DP = 20;
var RM = 1;
var MAX_DP = 1e6;
var MAX_POWER = 1e6;
var NE = -7;
var PE = 21;
var STRICT = false;
var NAME = "[big.js] ";
var INVALID = NAME + "Invalid ";
var INVALID_DP = INVALID + "decimal places";
var INVALID_RM = INVALID + "rounding mode";
var DIV_BY_ZERO = NAME + "Division by zero";
var P = {};
var UNDEFINED = void 0;
var NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i;
function _Big_() {
function Big2(n) {
var x = this;
if (!(x instanceof Big2)) return n === UNDEFINED ? _Big_() : new Big2(n);
if (n instanceof Big2) {
x.s = n.s;
x.e = n.e;
x.c = n.c.slice();
} else {
if (typeof n !== "string") {
if (Big2.strict === true && typeof n !== "bigint") {
throw TypeError(INVALID + "value");
}
n = n === 0 && 1 / n < 0 ? "-0" : String(n);
}
parse(x, n);
}
x.constructor = Big2;
}
Big2.prototype = P;
Big2.DP = DP;
Big2.RM = RM;
Big2.NE = NE;
Big2.PE = PE;
Big2.strict = STRICT;
Big2.roundDown = 0;
Big2.roundHalfUp = 1;
Big2.roundHalfEven = 2;
Big2.roundUp = 3;
return Big2;
}
function parse(x, n) {
var e, i, nl;
if (!NUMERIC.test(n)) {
throw Error(INVALID + "number");
}
x.s = n.charAt(0) == "-" ? (n = n.slice(1), -1) : 1;
if ((e = n.indexOf(".")) > -1) n = n.replace(".", "");
if ((i = n.search(/e/i)) > 0) {
if (e < 0) e = i;
e += +n.slice(i + 1);
n = n.substring(0, i);
} else if (e < 0) {
e = n.length;
}
nl = n.length;
for (i = 0; i < nl && n.charAt(i) == "0"; ) ++i;
if (i == nl) {
x.c = [x.e = 0];
} else {
for (; nl > 0 && n.charAt(--nl) == "0"; ) ;
x.e = e - i - 1;
x.c = [];
for (e = 0; i <= nl; ) x.c[e++] = +n.charAt(i++);
}
return x;
}
function round(x, sd, rm, more) {
var xc = x.c;
if (rm === UNDEFINED) rm = x.constructor.RM;
if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) {
throw Error(INVALID_RM);
}
if (sd < 1) {
more = rm === 3 && (more || !!xc[0]) || sd === 0 && (rm === 1 && xc[0] >= 5 || rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED)));
xc.length = 1;
if (more) {
x.e = x.e - sd + 1;
xc[0] = 1;
} else {
xc[0] = x.e = 0;
}
} else if (sd < xc.length) {
more = rm === 1 && xc[sd] >= 5 || rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || rm === 3 && (more || !!xc[0]);
xc.length = sd;
if (more) {
for (; ++xc[--sd] > 9; ) {
xc[sd] = 0;
if (sd === 0) {
++x.e;
xc.unshift(1);
break;
}
}
}
for (sd = xc.length; !xc[--sd]; ) xc.pop();
}
return x;
}
function stringify(x, doExponential, isNonzero) {
var e = x.e, s = x.c.join(""), n = s.length;
if (doExponential) {
s = s.charAt(0) + (n > 1 ? "." + s.slice(1) : "") + (e < 0 ? "e" : "e+") + e;
} else if (e < 0) {
for (; ++e; ) s = "0" + s;
s = "0." + s;
} else if (e > 0) {
if (++e > n) {
for (e -= n; e--; ) s += "0";
} else if (e < n) {
s = s.slice(0, e) + "." + s.slice(e);
}
} else if (n > 1) {
s = s.charAt(0) + "." + s.slice(1);
}
return x.s < 0 && isNonzero ? "-" + s : s;
}
P.abs = function() {
var x = new this.constructor(this);
x.s = 1;
return x;
};
P.cmp = function(y) {
var isneg, x = this, xc = x.c, yc = (y = new x.constructor(y)).c, i = x.s, j = y.s, k = x.e, l = y.e;
if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i;
if (i != j) return i;
isneg = i < 0;
if (k != l) return k > l ^ isneg ? 1 : -1;
j = (k = xc.length) < (l = yc.length) ? k : l;
for (i = -1; ++i < j; ) {
if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1;
}
return k == l ? 0 : k > l ^ isneg ? 1 : -1;
};
P.div = function(y) {
var x = this, Big2 = x.constructor, a = x.c, b = (y = new Big2(y)).c, k = x.s == y.s ? 1 : -1, dp = Big2.DP;
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
throw Error(INVALID_DP);
}
if (!b[0]) {
throw Error(DIV_BY_ZERO);
}
if (!a[0]) {
y.s = k;
y.c = [y.e = 0];
return y;
}
var bl, bt, n, cmp, ri, bz = b.slice(), ai = bl = b.length, al = a.length, r = a.slice(0, bl), rl = r.length, q = y, qc = q.c = [], qi = 0, p = dp + (q.e = x.e - y.e) + 1;
q.s = k;
k = p < 0 ? 0 : p;
bz.unshift(0);
for (; rl++ < bl; ) r.push(0);
do {
for (n = 0; n < 10; n++) {
if (bl != (rl = r.length)) {
cmp = bl > rl ? 1 : -1;
} else {
for (ri = -1, cmp = 0; ++ri < bl; ) {
if (b[ri] != r[ri]) {
cmp = b[ri] > r[ri] ? 1 : -1;
break;
}
}
}
if (cmp < 0) {
for (bt = rl == bl ? b : bz; rl; ) {
if (r[--rl] < bt[rl]) {
ri = rl;
for (; ri && !r[--ri]; ) r[ri] = 9;
--r[ri];
r[rl] += 10;
}
r[rl] -= bt[rl];
}
for (; !r[0]; ) r.shift();
} else {
break;
}
}
qc[qi++] = cmp ? n : ++n;
if (r[0] && cmp) r[rl] = a[ai] || 0;
else r = [a[ai]];
} while ((ai++ < al || r[0] !== UNDEFINED) && k--);
if (!qc[0] && qi != 1) {
qc.shift();
q.e--;
p--;
}
if (qi > p) round(q, p, Big2.RM, r[0] !== UNDEFINED);
return q;
};
P.eq = function(y) {
return this.cmp(y) === 0;
};
P.gt = function(y) {
return this.cmp(y) > 0;
};
P.gte = function(y) {
return this.cmp(y) > -1;
};
P.lt = function(y) {
return this.cmp(y) < 0;
};
P.lte = function(y) {
return this.cmp(y) < 1;
};
P.minus = P.sub = function(y) {
var i, j, t, xlty, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s;
if (a != b) {
y.s = -b;
return x.plus(y);
}
var xc = x.c.slice(), xe = x.e, yc = y.c, ye = y.e;
if (!xc[0] || !yc[0]) {
if (yc[0]) {
y.s = -b;
} else if (xc[0]) {
y = new Big2(x);
} else {
y.s = 1;
}
return y;
}
if (a = xe - ye) {
if (xlty = a < 0) {
a = -a;
t = xc;
} else {
ye = xe;
t = yc;
}
t.reverse();
for (b = a; b--; ) t.push(0);
t.reverse();
} else {
j = ((xlty = xc.length < yc.length) ? xc : yc).length;
for (a = b = 0; b < j; b++) {
if (xc[b] != yc[b]) {
xlty = xc[b] < yc[b];
break;
}
}
}
if (xlty) {
t = xc;
xc = yc;
yc = t;
y.s = -y.s;
}
if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--; ) xc[i++] = 0;
for (b = i; j > a; ) {
if (xc[--j] < yc[j]) {
for (i = j; i && !xc[--i]; ) xc[i] = 9;
--xc[i];
xc[j] += 10;
}
xc[j] -= yc[j];
}
for (; xc[--b] === 0; ) xc.pop();
for (; xc[0] === 0; ) {
xc.shift();
--ye;
}
if (!xc[0]) {
y.s = 1;
xc = [ye = 0];
}
y.c = xc;
y.e = ye;
return y;
};
P.mod = function(y) {
var ygtx, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s;
if (!y.c[0]) {
throw Error(DIV_BY_ZERO);
}
x.s = y.s = 1;
ygtx = y.cmp(x) == 1;
x.s = a;
y.s = b;
if (ygtx) return new Big2(x);
a = Big2.DP;
b = Big2.RM;
Big2.DP = Big2.RM = 0;
x = x.div(y);
Big2.DP = a;
Big2.RM = b;
return this.minus(x.times(y));
};
P.neg = function() {
var x = new this.constructor(this);
x.s = -x.s;
return x;
};
P.plus = P.add = function(y) {
var e, k, t, x = this, Big2 = x.constructor;
y = new Big2(y);
if (x.s != y.s) {
y.s = -y.s;
return x.minus(y);
}
var xe = x.e, xc = x.c, ye = y.e, yc = y.c;
if (!xc[0] || !yc[0]) {
if (!yc[0]) {
if (xc[0]) {
y = new Big2(x);
} else {
y.s = x.s;
}
}
return y;
}
xc = xc.slice();
if (e = xe - ye) {
if (e > 0) {
ye = xe;
t = yc;
} else {
e = -e;
t = xc;
}
t.reverse();
for (; e--; ) t.push(0);
t.reverse();
}
if (xc.length - yc.length < 0) {
t = yc;
yc = xc;
xc = t;
}
e = yc.length;
for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0;
if (k) {
xc.unshift(k);
++ye;
}
for (e = xc.length; xc[--e] === 0; ) xc.pop();
y.c = xc;
y.e = ye;
return y;
};
P.pow = function(n) {
var x = this, one = new x.constructor("1"), y = one, isneg = n < 0;
if (n !== ~~n || n < -1e6 || n > MAX_POWER) {
throw Error(INVALID + "exponent");
}
if (isneg) n = -n;
for (; ; ) {
if (n & 1) y = y.times(x);
n >>= 1;
if (!n) break;
x = x.times(x);
}
return isneg ? one.div(y) : y;
};
P.prec = function(sd, rm) {
if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
throw Error(INVALID + "precision");
}
return round(new this.constructor(this), sd, rm);
};
P.round = function(dp, rm) {
if (dp === UNDEFINED) dp = 0;
else if (dp !== ~~dp || dp < -1e6 || dp > MAX_DP) {
throw Error(INVALID_DP);
}
return round(new this.constructor(this), dp + this.e + 1, rm);
};
P.sqrt = function() {
var r, c, t, x = this, Big2 = x.constructor, s = x.s, e = x.e, half = new Big2("0.5");
if (!x.c[0]) return new Big2(x);
if (s < 0) {
throw Error(NAME + "No square root");
}
s = Math.sqrt(+stringify(x, true, true));
if (s === 0 || s === 1 / 0) {
c = x.c.join("");
if (!(c.length + e & 1)) c += "0";
s = Math.sqrt(c);
e = ((e + 1) / 2 | 0) - (e < 0 || e & 1);
r = new Big2((s == 1 / 0 ? "5e" : (s = s.toExponential()).slice(0, s.indexOf("e") + 1)) + e);
} else {
r = new Big2(s + "");
}
e = r.e + (Big2.DP += 4);
do {
t = r;
r = half.times(t.plus(x.div(t)));
} while (t.c.slice(0, e).join("") !== r.c.slice(0, e).join(""));
return round(r, (Big2.DP -= 4) + r.e + 1, Big2.RM);
};
P.times = P.mul = function(y) {
var c, x = this, Big2 = x.constructor, xc = x.c, yc = (y = new Big2(y)).c, a = xc.length, b = yc.length, i = x.e, j = y.e;
y.s = x.s == y.s ? 1 : -1;
if (!xc[0] || !yc[0]) {
y.c = [y.e = 0];
return y;
}
y.e = i + j;
if (a < b) {
c = xc;
xc = yc;
yc = c;
j = a;
a = b;
b = j;
}
for (c = new Array(j = a + b); j--; ) c[j] = 0;
for (i = b; i--; ) {
b = 0;
for (j = a + i; j > i; ) {
b = c[j] + yc[i] * xc[j - i - 1] + b;
c[j--] = b % 10;
b = b / 10 | 0;
}
c[j] = b;
}
if (b) ++y.e;
else c.shift();
for (i = c.length; !c[--i]; ) c.pop();
y.c = c;
return y;
};
P.toExponential = function(dp, rm) {
var x = this, n = x.c[0];
if (dp !== UNDEFINED) {
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
throw Error(INVALID_DP);
}
x = round(new x.constructor(x), ++dp, rm);
for (; x.c.length < dp; ) x.c.push(0);
}
return stringify(x, true, !!n);
};
P.toFixed = function(dp, rm) {
var x = this, n = x.c[0];
if (dp !== UNDEFINED) {
if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {
throw Error(INVALID_DP);
}
x = round(new x.constructor(x), dp + x.e + 1, rm);
for (dp = dp + x.e + 1; x.c.length < dp; ) x.c.push(0);
}
return stringify(x, false, !!n);
};
P[Symbol.for("nodejs.util.inspect.custom")] = P.toJSON = P.toString = function() {
var x = this, Big2 = x.constructor;
return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, !!x.c[0]);
};
P.toNumber = function() {
var n = +stringify(this, true, true);
if (this.constructor.strict === true && !this.eq(n.toString())) {
throw Error(NAME + "Imprecise conversion");
}
return n;
};
P.toPrecision = function(sd, rm) {
var x = this, Big2 = x.constructor, n = x.c[0];
if (sd !== UNDEFINED) {
if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {
throw Error(INVALID + "precision");
}
x = round(new Big2(x), sd, rm);
for (; x.c.length < sd; ) x.c.push(0);
}
return stringify(x, sd <= x.e || x.e <= Big2.NE || x.e >= Big2.PE, !!n);
};
P.valueOf = function() {
var x = this, Big2 = x.constructor;
if (Big2.strict === true) {
throw Error(NAME + "valueOf disallowed");
}
return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, true);
};
var Big = _Big_();
var big_default = Big;
// ../../packages/tools/src/grid/calcGridStepSize.ts
function calcGridStepSize(highPrice, lowPrice, gridLevels) {
return big_default(highPrice).minus(lowPrice).div(gridLevels - 1).toNumber();
}
// ../../packages/tools/src/grid/calcGridLines.ts
function calcGridLines(highPrice, lowPrice, gridLevels, quantity) {
const gridStepSize = calcGridStepSize(
highPrice,
lowPrice,
gridLevels
);
return Array.from({ length: gridLevels }).map((_, i) => ({
price: big_default(lowPrice).plus(big_default(gridStepSize).mul(i)).toNumber(),
quantity
}));
}
// ../../packages/tools/src/currency/common/getExponentAbs.ts
function getExponentAbs(numberLike) {
const number = new big_default(numberLike);
return Math.abs(number.e);
}
// ../../packages/tools/src/grid/isWaitingGridLine.ts
function isWaitingGridLine(gridLine, gridLines, currentAssetPrice) {
const gridLineIndex = gridLines.findIndex(
(gridLineItem) => gridLineItem.price === gridLine.price && gridLineItem.quantity === gridLine.quantity
);
if (gridLineIndex === -1) {
throw new Error(
`Cannot find grid line index of { price: ${gridLine.price}, quantity: ${gridLine.quantity} }`
);
}
const targetGridLine = gridLines[gridLineIndex];
const prevGridLine = gridLines[gridLineIndex - 1];
const nextGridLine = gridLines[gridLineIndex + 1];
const targetGridLinePriceDiff = big_default(currentAssetPrice).minus(targetGridLine.price).abs();
if (prevGridLine) {
const prevGridLinePriceDiff = big_default(currentAssetPrice).minus(prevGridLine.price).abs();
if (big_default(prevGridLinePriceDiff).lt(targetGridLinePriceDiff)) {
return false;
}
}
if (nextGridLine) {
const nextGridLinePriceDiff = big_default(currentAssetPrice).minus(nextGridLine.price).abs();
if (big_default(nextGridLinePriceDiff).lte(targetGridLinePriceDiff)) {
return false;
}
}
return true;
}
// ../../packages/tools/src/grid/nextGridLinePrice.ts
function nextGridLinePrice(gridLines, currentGridLineIndex) {
const nextGridLine = gridLines[currentGridLineIndex + 1];
if (!nextGridLine) {
throw new Error(
`nextGridLinePrice: Grid line at index ${currentGridLineIndex} doesn't exists`
);
}
return nextGridLine.price;
}
// ../../packages/tools/src/grid/computeGridLevelsFromCurrentAssetPrice.ts
function computeGridLevelsFromCurrentAssetPrice(gridLines, currentAssetPrice) {
return gridLines.flatMap((gridLine, i) => {
if (i === gridLines.length - 1) {
return [];
}
const sellOrderPrice = nextGridLinePrice(gridLines, i);
if (isWaitingGridLine(gridLine, gridLines, currentAssetPrice) || gridLine.price > currentAssetPrice) {
const gridLevel2 = {
buy: {
price: gridLine.price,
quantity: gridLine.quantity,
status: XOrderStatus.Filled
},
sell: {
price: sellOrderPrice,
quantity: gridLine.quantity,
status: XOrderStatus.Idle
}
};
return [gridLevel2];
}
const gridLevel = {
buy: {
price: gridLine.price,
quantity: gridLine.quantity,
status: XOrderStatus.Idle
},
sell: {
price: sellOrderPrice,
quantity: gridLine.quantity,
status: XOrderStatus.Idle
}
};
return [gridLevel];
});
}
// ../../packages/tools/src/dca/utils.ts
var isGroup = (rule) => {
return !!rule?.rules;
};
var toIndicatorOptions = (name, indicator) => {
switch (name) {
case "RSI":
case "EMA":
case "SMA":
return { periods: Number(indicator.periods) };
default:
throw new Error(`toIndicatorOptions: Unsupported indicator ${name}`);
}
};
// ../../packages/tools/src/dca/evaluateConditions.ts
function evaluateConditions(entryConditions, indicators) {
const expressions = [];
for (const rule of entryConditions.rules) {
if (isGroup(rule)) {
expressions.push(evaluateConditions(rule, indicators));
} else {
if (isIndicatorValue(rule.value)) {
const indicatorValue = indicators[rule.field]?.[rule.value.timeframe]?.[JSON.stringify(toIndicatorOptions(rule.field, rule.value))];
if (indicatorValue === void 0) {
console.warn(
`No indicator value provided for ${rule.field} ${rule.value.timeframe}. Skipping the rule.`,
indicators
);
continue;
}
expressions.push(evaluate(rule.operator, indicatorValue, Number(rule.value.indicatorValue)));
} else {
console.warn(`Non indicator rule provided. Default to: false`, rule);
expressions.push(false);
}
}
}
return combine(entryConditions.combinator, expressions);
}
function evaluate(operator, value1, value2) {
switch (operator) {
case "=":
return value1 === value2;
case "!=":
return value1 !== value2;
case "<":
return value1 < value2;
case ">":
return value1 > value2;
case "<=":
return value1 <= value2;
case ">=":
return value1 >= value2;
default:
throw new Error(`Unsupported operator: ${operator}`);
}
}
function combine(combinator, expressions) {
if (combinator === "and") {
return expressions.every(Boolean);
} else if (combinator === "or") {
return expressions.some(Boolean);
} else {
throw new Error(`Unsupported combinator: ${combinator}`);
}
}
// ../../packages/tools/src/dca/extractIndicators.ts
function extractIndicators(entryConditions) {
const result = [];
for (const rule of entryConditions.rules) {
if (isGroup(rule)) {
result.push(...extractIndicators(rule));
} else {
if (isIndicatorValue(rule.value)) {
result.push([rule.field, rule.value.timeframe, { periods: Number(rule.value.periods) }]);
}
}
}
return result.filter((value, index, array) => {
return array.indexOf(value) === index;
});
}
// ../../packages/tools/src/candlesticks/barSizeToDuration.ts
var ONE_MINUTE = 60 * 1e3;
var ONE_HOUR = 60 * ONE_MINUTE;
var ONE_DAY = 24 * ONE_HOUR;
var barSizeDurationMap = {
"1m": ONE_MINUTE,
"5m": 5 * ONE_MINUTE,
"15m": 15 * ONE_MINUTE,
"1h": ONE_HOUR,
"4h": 4 * ONE_HOUR,
"1d": ONE_DAY,
"1w": 7 * ONE_DAY,
"1M": 30 * ONE_DAY,
// may require special approach because number of days in a month is not fixed
"3M": 90 * ONE_DAY
// may require special approach because number of days in a month is not fixed
};
function barSizeToDuration(barSize) {
return barSizeDurationMap[barSize];
}
// ../../packages/tools/src/candlesticks/aggregateCandles.ts
function aggregateCandles(candles, timeframe) {
if (timeframe === BarSize.ONE_MINUTE) {
return candles;
}
const barSizeInMinutes = barSizeToDuration(timeframe) / 6e4;
const oneMinuteCandles = [...candles];
const resultCandles = [];
while (oneMinuteCandles.length >= barSizeInMinutes) {
resultCandles.push(aggregate(oneMinuteCandles.splice(0, barSizeInMinutes)));
}
return resultCandles;
}
function aggregate(candles) {
return {
open: candles[0].open,
high: candles.reduce((acc, candle) => Math.max(acc, candle.high), 0),
low: candles.reduce((acc, candle) => Math.min(acc, candle.low), Infinity),
close: candles[candles.length - 1].close,
timestamp: candles[0].timestamp
};
}
// ../../packages/tools/src/dca/requiredHistory.ts
function requiredHistory(indicatorsOptions) {
return indicatorsOptions.reduce((acc, [, timeframe, options]) => {
const { periods } = options;
const barSizeInMinutes = barSizeToDuration(timeframe) / 6e4;
const requiredHistory2 = barSizeInMinutes * periods;
if (requiredHistory2 > acc) {
return requiredHistory2;
}
return acc;
}, 0);
}
// ../../packages/tools/src/symbolId/constants.ts
var EXCHANGE_CODE_DELIMITER = ":";
var CURRENCY_PAIR_DELIMITER = "/";
// ../../packages/tools/src/symbolId/composeSymbolIdFromPair.ts
function composeSymbolIdFromPair(exchangeCode, currencyPair) {
return `${exchangeCode.toUpperCase()}${EXCHANGE_CODE_DELIMITER}${currencyPair}`;
}
// ../../packages/tools/src/symbolId/isValidSymbolId.ts
var exchangeCodes = Object.keys(ExchangeCode);
var spotSymbolPattern = `^(${exchangeCodes.join(
"|"
)})${EXCHANGE_CODE_DELIMITER}[A-Z0-9]+${CURRENCY_PAIR_DELIMITER}[A-Z0-9]+$`;
var futuresSymbolPattern = `^(${exchangeCodes.join(
"|"
)})${EXCHANGE_CODE_DELIMITER}[A-Z0-9]+${CURRENCY_PAIR_DELIMITER}[A-Z0-9]+${EXCHANGE_CODE_DELIMITER}[A-Z0-9]+$`;
function isValidSymbolId(symbolId) {
return new RegExp(spotSymbolPattern).test(symbolId) || new RegExp(futuresSymbolPattern).test(symbolId);
}
// ../../packages/tools/src/symbolId/decomposeSymbolId.ts
function decomposeSymbolId(symbolId) {
if (!isValidSymbolId(symbolId)) {
throw new Error(`${symbolId} is not a valid symbolId`);
}
const [exchangeCodeKey, currencyPairSymbol, futuresCoin] = symbolId.split(EXCHANGE_CODE_DELIMITER);
const [baseCurrency, quoteCurrency] = currencyPairSymbol.split(CURRENCY_PAIR_DELIMITER);
return {
exchangeCode: ExchangeCode[exchangeCodeKey],
currencyPairSymbol: futuresCoin ? currencyPairSymbol + EXCHANGE_CODE_DELIMITER + futuresCoin : currencyPairSymbol,
baseCurrency,
quoteCurrency
};
}
// ../../packages/tools/src/symbolId/isValidSymbol.ts
function isValidSymbol(symbol) {
const symbolPattern = `^[A-Z0-9]+${CURRENCY_PAIR_DELIMITER}[A-Z0-9]+$`;
return new RegExp(symbolPattern).test(symbol);
}
// ../../packages/tools/src/symbol/decomposeSymbol.ts
function decomposeSymbol(symbol) {
const [baseCurrency = "NONE", quoteCurrency = "NONE"] = symbol.split("/");
return {
baseCurrency,
quoteCurrency
};
}
// ../../packages/bot-processor/src/effect-runner.ts
var effectRunnerMap = {
[USE_SMART_TRADE]: runUseSmartTradeEffect,
[GET_SMART_TRADE]: runGetSmartTradeEffect,
[CANCEL_SMART_TRADE]: runCancelSmartTradeEffect,
[CREATE_SMART_TRADE]: runCreateSmartTradeEffect,
[REPLACE_SMART_TRADE]: runReplaceSmartTradeEffect,
[USE_TRADE]: runUseTradeEffect,
[USE_ARB_TRADE]: runUseArbTradeEffect,
[USE_DCA]: runUseDcaEffect,
[BUY]: runBuyEffect,
[SELL]: runSellEffect,
[USE_EXCHANGE]: runUseExchangeEffect,
[USE_INDICATOR]: runUseIndicatorEffect,
[USE_INDICATORS]: runUseIndicatorsEffect,
[USE_MARKET]: runUseMarketEffect,
[USE_CANDLE]: runUseCandleEffect,
[USE_RSI_INDICATOR]: runUseRsiIndicatorEffect
};
async function runUseSmartTradeEffect(effect, ctx) {
const { entry, tp, sl, quantity } = effect.payload;
const smartTrade = await ctx.control.getOrCreateSmartTrade(effect.ref, {
type: "Trade",
entry: { quantity, ...entry },
tp: tp ? { quantity, ...tp } : void 0,
sl: sl ? { quantity, ...sl } : void 0
});
return new SmartTradeService(effect.ref, smartTrade);
}
async function runGetSmartTradeEffect(effect, ctx) {
const smartTrade = await ctx.control.getSmartTrade(effect.ref);
return smartTrade ? new SmartTradeService(effect.ref, smartTrade) : null;
}
async function runCancelSmartTradeEffect(effect, ctx) {
return ctx.control.cancelSmartTrade(effect.ref);
}
async function runCreateSmartTradeEffect(effect, ctx) {
const { entry, tp, sl, quantity } = effect.payload;
const smartTrade = await ctx.control.createSmartTrade(effect.ref, {
type: "Trade",
entry: { quantity, ...entry },
tp: tp ? { quantity, ...tp } : void 0,
sl: sl ? { quantity, ...sl } : void 0
});
return new SmartTradeService(effect.ref, smartTrade);
}
async function runReplaceSmartTradeEffect(effect, ctx) {
const smartTrade = await ctx.control.replaceSmartTrade(effect.ref, effect.payload);
return new SmartTradeService(effect.ref, smartTrade);
}
async function runUseTradeEffect(effect, ctx) {
throw new Error("useTrade is deprecated");
}
async function runUseArbTradeEffect(effect, ctx) {
const { payload, ref } = effect;
const smartTrade = await ctx.control.getOrCreateSmartTrade(ref, {
type: "ARB",
entry: {
exchangeAccountId: payload.exchange1,
symbol: payload.symbol,
side: XOrderSide.Buy,
type: payload.price ? XOrderType.Limit : XOrderType.Market,
price: payload.price,
quantity: payload.quantity
},
tp: {
exchangeAccountId: payload.exchange2,
symbol: payload.symbol,
side: XOrderSide.Sell,
type: payload.tp ? XOrderType.Limit : XOrderType.Market,
price: payload.tp,
quantity: payload.quantity
}
});
return new SmartTradeService(effect.ref, smartTrade);
}
async function runUseDcaEffect(effect, ctx) {
const { payload, ref } = effect;
const smartTrade = await ctx.control.getOrCreateSmartTrade(ref, {
type: "DCA",
entry: {
symbol: payload.symbol,
type: payload.price ? XOrderType.Limit : XOrderType.Market,
side: XOrderSide.Buy,
price: payload.price,
quantity: payload.quantity
},
tp: {
symbol: payload.symbol,
type: XOrderType.Limit,
side: XOrderSide.Sell,
relativePrice: payload.tpPercent,
quantity: payload.quantity
},
sl: payload.slPercent ? {
symbol: payload.symbol,
type: XOrderType.Market,
side: XOrderSide.Sell,
relativePrice: -payload.slPercent,
quantity: payload.quantity
} : void 0,
safetyOrders: payload.safetyOrders.map((order) => ({
relativePrice: order.relativePrice,
quantity: order.quantity,
symbol: payload.symbol,