mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 01:08:07 +00:00
feat: 添加 EdgeX 交易所适配器及相关客户端实现,支持订单、深度和K线数据处理
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import { strict as assert } from "assert";
|
||||
|
||||
export function countBase10Scale(resolution: bigint): number {
|
||||
let scale = 0;
|
||||
let value = resolution;
|
||||
while (value % 10n === 0n) {
|
||||
value /= 10n;
|
||||
scale += 1;
|
||||
}
|
||||
if (value !== 1n) {
|
||||
throw new Error(`Resolution ${resolution.toString()} is not a power of 10`);
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
export function decimalToBigInt(value: number | string, scale: number): bigint {
|
||||
const normalized = normalizeDecimal(typeof value === "number" ? value.toString() : value);
|
||||
const [intPart, fracPart = ""] = normalized.split(".");
|
||||
assert(fracPart.length <= scale, `Value ${value} exceeds scale ${scale}`);
|
||||
const paddedFraction = (fracPart + "0".repeat(scale)).slice(0, scale);
|
||||
const digits = stripLeadingZeros(intPart + paddedFraction);
|
||||
return digits.length === 0 ? 0n : BigInt(digits);
|
||||
}
|
||||
|
||||
export function bigIntToDecimal(value: bigint, scale: number): string {
|
||||
const negative = value < 0n;
|
||||
const abs = negative ? -value : value;
|
||||
const factor = 10n ** BigInt(scale);
|
||||
const intPart = abs / factor;
|
||||
const fracPart = abs % factor;
|
||||
if (scale === 0) {
|
||||
return `${negative ? "-" : ""}${intPart.toString()}`;
|
||||
}
|
||||
const fracStr = fracPart.toString().padStart(scale, "0").replace(/0+$/, "");
|
||||
if (fracStr.length === 0) {
|
||||
return `${negative ? "-" : ""}${intPart.toString()}`;
|
||||
}
|
||||
return `${negative ? "-" : ""}${intPart.toString()}.${fracStr}`;
|
||||
}
|
||||
|
||||
export function multiplyByDecimal(value: bigint, rate: string, roundUp = false): bigint {
|
||||
const { numerator, denominator } = decimalToFraction(rate);
|
||||
const product = value * numerator;
|
||||
if (!roundUp) {
|
||||
return product / denominator;
|
||||
}
|
||||
return (product + denominator - 1n) / denominator;
|
||||
}
|
||||
|
||||
export function decimalToFraction(value: string): { numerator: bigint; denominator: bigint } {
|
||||
const normalized = normalizeDecimal(value);
|
||||
if (!normalized.includes(".")) {
|
||||
return { numerator: BigInt(normalized), denominator: 1n };
|
||||
}
|
||||
const negative = normalized.startsWith("-");
|
||||
const unsigned = negative ? normalized.slice(1) : normalized;
|
||||
const parts = unsigned.split(".");
|
||||
const intPart = parts[0] ?? "0";
|
||||
const fracPart = parts[1] ?? "";
|
||||
const denominator = 10n ** BigInt(fracPart.length);
|
||||
const magnitude = BigInt(stripLeadingZeros(intPart + fracPart));
|
||||
const numerator = negative ? -magnitude : magnitude;
|
||||
return { numerator, denominator };
|
||||
}
|
||||
|
||||
export function getScaleFromDenominator(denominator: bigint): number {
|
||||
let scale = 0;
|
||||
let value = denominator;
|
||||
while (value > 1n) {
|
||||
if (value % 10n !== 0n) {
|
||||
throw new Error(`Denominator ${denominator.toString()} is not a power of 10`);
|
||||
}
|
||||
value /= 10n;
|
||||
scale += 1;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
export function formatDecimal(numerator: bigint, scale: number): string {
|
||||
const negative = numerator < 0n;
|
||||
let absValue = negative ? -numerator : numerator;
|
||||
if (scale === 0) {
|
||||
return `${negative ? "-" : ""}${absValue.toString()}`;
|
||||
}
|
||||
const factor = 10n ** BigInt(scale);
|
||||
const intPart = absValue / factor;
|
||||
let fracPart = (absValue % factor).toString().padStart(scale, "0");
|
||||
fracPart = fracPart.replace(/0+$/, "");
|
||||
if (fracPart.length === 0) {
|
||||
return `${negative ? "-" : ""}${intPart.toString()}`;
|
||||
}
|
||||
return `${negative ? "-" : ""}${intPart.toString()}.${fracPart}`;
|
||||
}
|
||||
|
||||
function normalizeDecimal(input: string): string {
|
||||
const trimmed = input.trim();
|
||||
if (!/^[-+]?((\d+\.?\d*)|(\.\d+))$/.test(trimmed)) {
|
||||
throw new Error(`Invalid decimal value: ${input}`);
|
||||
}
|
||||
const negative = trimmed.startsWith("-");
|
||||
const unsigned = trimmed.replace(/^[-+]/, "");
|
||||
const [rawInt = "0", rawFrac = ""] = unsigned.split(".");
|
||||
const intDigits = stripLeadingZeros(rawInt);
|
||||
const fracDigits = rawFrac.replace(/0+$/, "");
|
||||
const magnitude = fracDigits.length > 0 ? `${intDigits}.${fracDigits}` : intDigits;
|
||||
if (magnitude === "0") {
|
||||
return "0";
|
||||
}
|
||||
return negative ? `-${magnitude}` : magnitude;
|
||||
}
|
||||
|
||||
function stripLeadingZeros(value: string): string {
|
||||
const stripped = value.replace(/^0+/, "");
|
||||
return stripped.length === 0 ? "0" : stripped;
|
||||
}
|
||||
Reference in New Issue
Block a user