Add Oxlint configuration and integrate linting commands

- Introduced a new `.oxlintrc.json` file to configure Oxlint for code quality checks.
- Updated `package.json` to include linting scripts (`lint` and `lint:fix`) for easier code maintenance.
- Enhanced documentation in `README` files to guide users on running Oxlint checks and applying fixes.
This commit is contained in:
discountry
2026-03-12 22:40:18 +08:00
parent 055bb445a9
commit eb70bab8c5
21 changed files with 95 additions and 46 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"ignorePatterns": [
"coverage/**",
"data/**",
"dist/**",
"docs/**",
"node_modules/**",
"out/**",
".tmp/**"
]
}
+4
View File
@@ -226,6 +226,8 @@ EXCHANGE=binance BINANCE_MARKET_TYPE=spot BINANCE_SYMBOL=BTCUSDT bun run index.t
bun run index.ts # 启动 CLI(默认入口) bun run index.ts # 启动 CLI(默认入口)
bun run start # 等价于运行 index.ts bun run start # 等价于运行 index.ts
bun run dev # 调试模式 bun run dev # 调试模式
bun run lint # 执行 Oxlint 检查
bun run lint:fix # 自动修复可安全修复的问题
bun x vitest run # 执行全部测试 bun x vitest run # 执行全部测试
``` ```
@@ -292,6 +294,8 @@ bun run pm2:start:offset
## 测试 ## 测试
项目使用 Vitest 项目使用 Vitest
```bash ```bash
bun run lint
bun run lint:fix
bun run test bun run test
bun x vitest --watch bun x vitest --watch
``` ```
+4
View File
@@ -222,6 +222,8 @@ Please keep these credentials safe and do not share them with anyone.
bun run index.ts # Launch the CLI (default entrypoint) bun run index.ts # Launch the CLI (default entrypoint)
bun run start # Alias for bun run index.ts bun run start # Alias for bun run index.ts
bun run dev # Development entrypoint bun run dev # Development entrypoint
bun run lint # Run Oxlint checks
bun run lint:fix # Apply safe Oxlint fixes
bun x vitest run # Execute the full Vitest suite bun x vitest run # Execute the full Vitest suite
``` ```
@@ -288,6 +290,8 @@ Run `pm2 save` afterwards if you want the process list to survive reboots.
## Testing ## Testing
Powered by Vitest: Powered by Vitest:
```bash ```bash
bun run lint
bun run lint:fix
bun run test bun run test
bun x vitest --watch bun x vitest --watch
``` ```
+41
View File
@@ -21,6 +21,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.9", "@types/bun": "^1.3.9",
"oxlint": "^1.54.0",
"vitest": "^4.0.18", "vitest": "^4.0.18",
}, },
"peerDependencies": { "peerDependencies": {
@@ -107,6 +108,44 @@
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
"@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.54.0", "", { "os": "android", "cpu": "arm" }, "sha512-khWlVXUa4CPvp4eXnj7/TUNeyiarwvTEmZggylPIPUCSWgPqUBFGElIBa9xKNCQt4pb+WSGArCNEAy22ekQQxg=="],
"@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.54.0", "", { "os": "android", "cpu": "arm64" }, "sha512-p3qEVSDVmyducpI9ORTJNbaMyXfICidDXGaf3WwyDyiXPExyZdfc6UsPepGPxImlfFJs5kxOCPqP4ut12Ed9pg=="],
"@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.54.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tUQ+vn/AL2P2Rz6cl3gsFA+4pMBFMRR0e6AVePoezV9iGTSMZUXIf0YWHq203bwNDXcY04vSXDqPB6E1b9WULA=="],
"@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.54.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-9tzH/OLGZCzVGEXW0D3I0OrQOOWciHYWV9mcxjqqQE6f1DMOXT23mWj5/OQtqhW3E1VfHf0uf2MzMbM2gboPlA=="],
"@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.54.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-XelGa+x7vC9epF5JzXWHaQtdxqcL5R+H2WcEkr+JDkfmY3dAXVLa+51qW3+MWt7CZanakaOyhraLzdM32pWFfg=="],
"@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t5FubAU899vMF+6rBtxDewkwSAeFn8OUCKb/+jJ1XqPU0FTR+RffnTfXafVE8WXw39eN4pzUK3rkxUWlcsFuaw=="],
"@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Du6cwkoMRi9DAgITzQpzS1QaEqE+5BP3Tfgr1yPy3C034n6IHISCwf4KMB+wojg8FE/kYvrJDibT0ENdcR3jUg=="],
"@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-R4PjJ1lfghsVBuAegW79jkvUWbN8P4F28KaKbM72dW6ZWTYMg6M0pkTilXFZ+q/mb8f0MEyR1rO16useoa6KTA=="],
"@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WBNFe1foIFg6ipgzjzJfDLn7C5nZpLr/UHlnlT7GI3scCD2xpJiJTGMTTpJqA8p0Q1l2NsEnAOj9PtreF0Tkzg=="],
"@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.54.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-M+UAW76rZHHiYKKy4e7Te5MNikANiFhYWl0qYF1MTIhQczYIqWVDQ+SX0SzW8ipOB/oK3+enOvlvJuhMoA968Q=="],
"@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-sGassljr8TR5F1WCqOaacrp3mYi107MnjkqlSXOMHACps7U2bL4v7M3RY7P7NMcGkNhzRHF3VO5+XyPWhTVM6w=="],
"@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-mW5Z6XTO8QWtlUjlf6yjntarjnbrmGVSK/V6XYy2rjH8xUfv9pn9G1vO92DBBBi0eUwnVpcOY3hMkP851WZNWg=="],
"@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.54.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-nfPmEGW9BfWEUD0PVXGaYa2RS4wVblofNih1gsyUoLSWSyliNisIWd7F+QXrDSL5SJ78BPZjDW6FainV8qRiTg=="],
"@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-gybxMQx4NN1T+pa8TLwgVS4u9H9Hxwm7Sl0qvnQJF2WRhNN1oTOCzkmmCBbW/29DYLeV99WU76zh7srCamK9yw=="],
"@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-EAXMh2w3pzSj/aiB67kXzcHIoKxAywC1i1IgxA1sLY7iffEaZowDTOJgirY7WxeR/WiiKwak89gPeh9wUdLnIw=="],
"@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.54.0", "", { "os": "none", "cpu": "arm64" }, "sha512-Ih7CfITkbw86+LjgV5gDwNmNQlvz7X+51gdeLLUDwuA/9lojDxCmRQEzeMl44KStQlwzCuNIcgGMae0MllV5ww=="],
"@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.54.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-qGQ8KIEfdgwwJd09Nc0d5hzlHQAM0EMoshMzHG/nNlMAHXrY7RFyat6VbzjflifAFb7LPAw+Yw9AB8cfzR7L8g=="],
"@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.54.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-GXos7N5oZIcIE8hlXgtUkI+y3frIqwiztx9p4+ZrpNgASbnIsxxy8bgLJqXE2SGCAdmtjBO1mdKhGTtVrb1jbg=="],
"@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-DVxSELcI72lmcODuVpO8uXkwuYPiA0hKMhBwNa8fO4+sIVxFvxugf/z6qrL+4PM8RjGWjdl8O/QqzuRWj9b5bA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.0", "", { "os": "android", "cpu": "arm" }, "sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.0", "", { "os": "android", "cpu": "arm" }, "sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.0", "", { "os": "android", "cpu": "arm64" }, "sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.0", "", { "os": "android", "cpu": "arm64" }, "sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ=="],
@@ -307,6 +346,8 @@
"ox": ["ox@0.12.4", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-+P+C7QzuwPV8lu79dOwjBKfB2CbnbEXe/hfyyrff1drrO1nOOj3Hc87svHfcW1yneRr3WXaKr6nz11nq+/DF9Q=="], "ox": ["ox@0.12.4", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-+P+C7QzuwPV8lu79dOwjBKfB2CbnbEXe/hfyyrff1drrO1nOOj3Hc87svHfcW1yneRr3WXaKr6nz11nq+/DF9Q=="],
"oxlint": ["oxlint@1.54.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.54.0", "@oxlint/binding-android-arm64": "1.54.0", "@oxlint/binding-darwin-arm64": "1.54.0", "@oxlint/binding-darwin-x64": "1.54.0", "@oxlint/binding-freebsd-x64": "1.54.0", "@oxlint/binding-linux-arm-gnueabihf": "1.54.0", "@oxlint/binding-linux-arm-musleabihf": "1.54.0", "@oxlint/binding-linux-arm64-gnu": "1.54.0", "@oxlint/binding-linux-arm64-musl": "1.54.0", "@oxlint/binding-linux-ppc64-gnu": "1.54.0", "@oxlint/binding-linux-riscv64-gnu": "1.54.0", "@oxlint/binding-linux-riscv64-musl": "1.54.0", "@oxlint/binding-linux-s390x-gnu": "1.54.0", "@oxlint/binding-linux-x64-gnu": "1.54.0", "@oxlint/binding-linux-x64-musl": "1.54.0", "@oxlint/binding-openharmony-arm64": "1.54.0", "@oxlint/binding-win32-arm64-msvc": "1.54.0", "@oxlint/binding-win32-ia32-msvc": "1.54.0", "@oxlint/binding-win32-x64-msvc": "1.54.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.15.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-ObSjVwf0ZYA5U5Cmelj0PsCuqCJXsm2TxZ40tgUSAY7Wu0lKAsNjor6cgXHXSys8jOwv1ICjtzouoWHdKGHbZg=="],
"patch-console": ["patch-console@2.0.0", "", {}, "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA=="], "patch-console": ["patch-console@2.0.0", "", {}, "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA=="],
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
+3
View File
@@ -14,6 +14,8 @@
"scripts": { "scripts": {
"dev": "bun run index.ts", "dev": "bun run index.ts",
"start": "bun run index.ts", "start": "bun run index.ts",
"lint": "oxlint",
"lint:fix": "oxlint --fix",
"test": "bun x vitest run", "test": "bun x vitest run",
"test:exchange-contract": "bun x vitest run tests/exchange-contract-suite.test.ts tests/exchange-factory.test.ts tests/config.test.ts", "test:exchange-contract": "bun x vitest run tests/exchange-contract-suite.test.ts tests/exchange-factory.test.ts tests/config.test.ts",
"test:watch": "bun x vitest", "test:watch": "bun x vitest",
@@ -27,6 +29,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.9", "@types/bun": "^1.3.9",
"oxlint": "^1.54.0",
"vitest": "^4.0.18" "vitest": "^4.0.18"
}, },
"peerDependencies": { "peerDependencies": {
+1 -1
View File
@@ -155,7 +155,7 @@ function parseExchangeCommand(
options: Record<string, string | boolean>, options: Record<string, string | boolean>,
common: CommandCommonOptions & { help?: boolean } common: CommandCommonOptions & { help?: boolean }
): ParsedCliCommand { ): ParsedCliCommand {
assertAllowedOptions(options, new Set([...GLOBAL_OPTION_NAMES])); assertAllowedOptions(options, new Set(GLOBAL_OPTION_NAMES));
if (action === "list") return { kind: "exchange-list", ...common }; if (action === "list") return { kind: "exchange-list", ...common };
if (action === "capabilities") return { kind: "exchange-capabilities", ...common }; if (action === "capabilities") return { kind: "exchange-capabilities", ...common };
throw new CommandParseError(`Unsupported exchange action '${action}'`); throw new CommandParseError(`Unsupported exchange action '${action}'`);
+6 -6
View File
@@ -543,7 +543,7 @@ export class AsterSpotRestClient {
} }
try { try {
return JSON.parse(text) as T; return JSON.parse(text) as T;
} catch (error) { } catch {
throw new Error(`[AsterSpotRestClient] 无法解析响应: ${text.slice(0, 200)}`); throw new Error(`[AsterSpotRestClient] 无法解析响应: ${text.slice(0, 200)}`);
} }
} }
@@ -795,7 +795,7 @@ export class AsterRestClient {
} }
try { try {
return JSON.parse(text) as AsterFuturesExchangeInfo; return JSON.parse(text) as AsterFuturesExchangeInfo;
} catch (error) { } catch {
throw new Error(`[AsterRestClient] 无法解析交易规则响应: ${text.slice(0, 200)}`); throw new Error(`[AsterRestClient] 无法解析交易规则响应: ${text.slice(0, 200)}`);
} }
} }
@@ -869,7 +869,7 @@ export class AsterRestClient {
try { try {
const payload = JSON.parse(text) as any[]; const payload = JSON.parse(text) as any[];
return payload.map((entry) => fromRestKline(entry, interval, upper)); return payload.map((entry) => fromRestKline(entry, interval, upper));
} catch (error) { } catch {
throw new Error(`[AsterRestClient] 无法解析K线响应: ${text.slice(0, 200)}`); throw new Error(`[AsterRestClient] 无法解析K线响应: ${text.slice(0, 200)}`);
} }
} }
@@ -899,7 +899,7 @@ export class AsterRestClient {
const payload = JSON.parse(text) as any; const payload = JSON.parse(text) as any;
// The response shape mirrors Binance: { symbol, markPrice, indexPrice, lastFundingRate, nextFundingTime, time } // The response shape mirrors Binance: { symbol, markPrice, indexPrice, lastFundingRate, nextFundingTime, time }
return payload; return payload;
} catch (error) { } catch {
throw new Error(`[AsterRestClient] 无法解析资金费率响应: ${text.slice(0, 200)}`); throw new Error(`[AsterRestClient] 无法解析资金费率响应: ${text.slice(0, 200)}`);
} }
} }
@@ -942,7 +942,7 @@ export class AsterRestClient {
} }
try { try {
return JSON.parse(text) as T; return JSON.parse(text) as T;
} catch (error) { } catch {
throw new Error(`[AsterRestClient] 无法解析响应: ${text.slice(0, 200)}`); throw new Error(`[AsterRestClient] 无法解析响应: ${text.slice(0, 200)}`);
} }
} }
@@ -1366,7 +1366,7 @@ export class AsterGateway {
}); });
} }
async ensureInitialized(symbol: string): Promise<void> { async ensureInitialized(_symbol: string): Promise<void> {
if (this.initialized) return; if (this.initialized) return;
if (this.initializing) return this.initializing; if (this.initializing) return this.initializing;
this.initializing = (async () => { this.initializing = (async () => {
+12 -17
View File
@@ -7,7 +7,6 @@ import ccxt, {
import NodeWebSocket from "ws"; import NodeWebSocket from "ws";
import { sign, utils as edUtils, hashes as edHashes } from "@noble/ed25519"; import { sign, utils as edUtils, hashes as edHashes } from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512"; import { sha512 } from "@noble/hashes/sha512";
import { randomBytes } from "crypto";
import type { import type {
AsterAccountSnapshot, AsterAccountSnapshot,
AsterAccountPosition, AsterAccountPosition,
@@ -137,17 +136,16 @@ export class BackpackGateway {
} }
private async doInitialize(symbol?: string): Promise<void> { private async doInitialize(symbol?: string): Promise<void> {
try { await this.exchange.loadMarkets();
await this.exchange.loadMarkets(); const requested = (symbol ?? this.symbol).toUpperCase();
const requested = (symbol ?? this.symbol).toUpperCase(); const market = this.findMarket(requested);
const market = this.findMarket(requested); if (!market) {
if (!market) { throw new Error(`Symbol ${requested} not found in Backpack markets`);
throw new Error(`Symbol ${requested} not found in Backpack markets`); }
} this.market = market;
this.market = market; this.marketSymbol = market.symbol;
this.marketSymbol = market.symbol; this.marketId = market.id;
this.marketId = market.id; this.isContractMarket = Boolean(market.contract);
this.isContractMarket = Boolean(market.contract);
if (process.env.BACKPACK_DEBUG === "1") { if (process.env.BACKPACK_DEBUG === "1") {
console.debug("[BackpackGateway] marketInfo", { console.debug("[BackpackGateway] marketInfo", {
userSymbol: this.symbol, userSymbol: this.symbol,
@@ -155,10 +153,7 @@ export class BackpackGateway {
marketId: this.marketId, marketId: this.marketId,
}); });
} }
this.initialized = true; this.initialized = true;
} catch (error) {
throw error;
}
} }
private findMarket(requested: string): any | null { private findMarket(requested: string): any | null {
@@ -774,7 +769,7 @@ export class BackpackGateway {
void this.resubscribeAllTopics(); void this.resubscribeAllTopics();
}; };
private handleWsClose = (event: any): void => { private handleWsClose = (_event: any): void => {
if (this.wsCleanup) { if (this.wsCleanup) {
try { try {
this.wsCleanup(); this.wsCleanup();
-3
View File
@@ -1,9 +1,6 @@
import ccxt, { import ccxt, {
type Balances, type Balances,
type Order as CcxtOrder, type Order as CcxtOrder,
type OrderBook as CcxtOrderBook,
type OHLCV as CcxtOhlcv,
type Ticker as CcxtTicker,
} from "ccxt"; } from "ccxt";
import axios from "axios"; import axios from "axios";
import { createHash } from "crypto"; import { createHash } from "crypto";
+1 -1
View File
@@ -1161,7 +1161,7 @@ function mapTicker(response: IApiTickerResponse, symbol: string): AsterTicker |
}; };
} }
function mapKlines(response: IApiCandlestickResponse, symbol: string): AsterKline[] { function mapKlines(response: IApiCandlestickResponse, _symbol: string): AsterKline[] {
return (response.result ?? []).reverse().map((entry) => ({ return (response.result ?? []).reverse().map((entry) => ({
openTime: nsToMs(entry.open_time ?? Date.now() * ONE_SECOND_IN_NANOSECONDS), openTime: nsToMs(entry.open_time ?? Date.now() * ONE_SECOND_IN_NANOSECONDS),
closeTime: nsToMs(entry.close_time ?? Date.now() * ONE_SECOND_IN_NANOSECONDS), closeTime: nsToMs(entry.close_time ?? Date.now() * ONE_SECOND_IN_NANOSECONDS),
+1 -4
View File
@@ -16,12 +16,10 @@ import type {
AsterTicker, AsterTicker,
CreateOrderParams, CreateOrderParams,
} from "../types"; } from "../types";
import { extractMessage } from "../../utils/errors";
import type { OrderSide, OrderType } from "../types"; import type { OrderSide, OrderType } from "../types";
import { LighterHttpClient } from "./http-client"; import { LighterHttpClient } from "./http-client";
import { HttpNonceManager } from "./nonce-manager"; import { HttpNonceManager } from "./nonce-manager";
import { LighterSigner, type CreateOrderSignParams } from "./signer"; import { LighterSigner, type CreateOrderSignParams } from "./signer";
import { bytesToHex } from "./bytes";
import type { import type {
LighterAccountDetails, LighterAccountDetails,
LighterAccountAsset, LighterAccountAsset,
@@ -39,7 +37,6 @@ import {
LIGHTER_HOSTS, LIGHTER_HOSTS,
LIGHTER_ORDER_TYPE, LIGHTER_ORDER_TYPE,
LIGHTER_TIME_IN_FORCE, LIGHTER_TIME_IN_FORCE,
DEFAULT_ORDER_EXPIRY_PLACEHOLDER,
IMMEDIATE_OR_CANCEL_EXPIRY_PLACEHOLDER, IMMEDIATE_OR_CANCEL_EXPIRY_PLACEHOLDER,
type LighterEnvironment, type LighterEnvironment,
} from "./constants"; } from "./constants";
@@ -2210,7 +2207,7 @@ function extractJsonRequestId(message: any): string | null {
function tryParseTxInfo(value: string): unknown { function tryParseTxInfo(value: string): unknown {
try { try {
return JSON.parse(value); return JSON.parse(value);
} catch (_) { } catch {
return value; return value;
} }
} }
+1 -1
View File
@@ -128,7 +128,7 @@ function computeExecutedQty(order: LighterOrder): string {
if (Number.isFinite(initial) && Number.isFinite(remaining)) { if (Number.isFinite(initial) && Number.isFinite(remaining)) {
return (initial - remaining).toString(); return (initial - remaining).toString();
} }
} catch (_) { } catch {
// fall through // fall through
} }
} }
+1 -1
View File
@@ -1684,7 +1684,7 @@ export class NadoGateway {
try { try {
const text = typeof data === "string" ? data : data.toString("utf8"); const text = typeof data === "string" ? data : data.toString("utf8");
message = JSON.parse(text); message = JSON.parse(text);
} catch (_error) { } catch {
return; return;
} }
if (!message || typeof message !== "object") return; if (!message || typeof message !== "object") return;
+3 -4
View File
@@ -32,7 +32,7 @@ function loadCcxtPro(): any | null {
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const mod = require("ccxt.pro"); const mod = require("ccxt.pro");
return mod?.default ?? mod; return mod?.default ?? mod;
} catch (_error) { } catch {
return null; return null;
} }
} }
@@ -571,7 +571,6 @@ export class ParadexGateway {
const market = typeof (this.exchange as any).market === "function" const market = typeof (this.exchange as any).market === "function"
? (this.exchange as any).market(symbol) ? (this.exchange as any).market(symbol)
: (this.exchange.markets ?? {})[symbol]; : (this.exchange.markets ?? {})[symbol];
const precisionDigits = Number((market?.precision?.amount ?? market?.amountPrecision));
const limitMin = Number(market?.limits?.amount?.min); const limitMin = Number(market?.limits?.amount?.min);
// Only trust explicit exchange min limit; do NOT infer 1 from precision=0 // Only trust explicit exchange min limit; do NOT infer 1 from precision=0
const minAmount = Number.isFinite(limitMin) && limitMin > 0 ? limitMin : undefined; const minAmount = Number.isFinite(limitMin) && limitMin > 0 ? limitMin : undefined;
@@ -593,7 +592,7 @@ export class ParadexGateway {
if (typeof (this.exchange as any).amountToPrecision === "function" && Number.isFinite(Number(amount))) { if (typeof (this.exchange as any).amountToPrecision === "function" && Number.isFinite(Number(amount))) {
amount = Number((this.exchange as any).amountToPrecision(symbol, amount)); amount = Number((this.exchange as any).amountToPrecision(symbol, amount));
} }
} catch (_normalizeError) { } catch {
// Swallow precision normalization errors and let exchange validation surface if any // Swallow precision normalization errors and let exchange validation surface if any
} }
@@ -944,7 +943,7 @@ export class ParadexGateway {
} }
} }
private updateOrdersFromRemote(open: CcxtOrder[], closed: CcxtOrder[]): void { private updateOrdersFromRemote(open: CcxtOrder[], _closed: CcxtOrder[]): void {
const nextOpen = new Map<string, AsterOrder>(); const nextOpen = new Map<string, AsterOrder>();
for (const order of open) { for (const order of open) {
-1
View File
@@ -4,7 +4,6 @@ import { App } from "./ui/App";
import { setupGlobalErrorHandlers } from "./runtime-errors"; import { setupGlobalErrorHandlers } from "./runtime-errors";
import { parseCliArgs, printCliHelp } from "./cli/args"; import { parseCliArgs, printCliHelp } from "./cli/args";
import { startStrategy } from "./cli/strategy-runner"; import { startStrategy } from "./cli/strategy-runner";
import { resolveExchangeId } from "./exchanges/create-adapter";
import { CommandParseError, parseCommandArgv, printCommandHelp } from "./cli/command-parser"; import { CommandParseError, parseCommandArgv, printCommandHelp } from "./cli/command-parser";
import { executeCliCommand, renderCommandPayload } from "./cli/command-executor"; import { executeCliCommand, renderCommandPayload } from "./cli/command-executor";
+1 -1
View File
@@ -409,7 +409,7 @@ export class BasisArbEngine {
if (!Number.isFinite(wallet) || !Number.isFinite(available)) continue; if (!Number.isFinite(wallet) || !Number.isFinite(available)) continue;
if (Math.abs(wallet) === 0 && Math.abs(available) === 0) continue; if (Math.abs(wallet) === 0 && Math.abs(available) === 0) continue;
const isTaggedFuturesAsset = /0$/.test(name); const isTaggedFuturesAsset = name.endsWith("0");
if (isTaggedFuturesAsset) { if (isTaggedFuturesAsset) {
futuresBalances.push({ asset: name.replace(/0$/, ""), wallet, available }); futuresBalances.push({ asset: name.replace(/0$/, ""), wallet, available });
continue; continue;
+1 -1
View File
@@ -461,7 +461,7 @@ export class GridEngine {
return false; return false;
} }
private async haltGrid(price: number): Promise<void> { private async haltGrid(_price: number): Promise<void> {
if (!this.running) return; if (!this.running) return;
const reason = this.stopReason ?? "触发网格止损"; const reason = this.stopReason ?? "触发网格止损";
this.log("warn", `${reason},开始执行平仓与撤单`); this.log("warn", `${reason},开始执行平仓与撤单`);
-1
View File
@@ -3,7 +3,6 @@ import type { ExchangeAdapter } from "../exchanges/adapter";
import type { import type {
AsterAccountSnapshot, AsterAccountSnapshot,
AsterDepth, AsterDepth,
AsterKline,
AsterOrder, AsterOrder,
AsterTicker, AsterTicker,
} from "../exchanges/types"; } from "../exchanges/types";
+1 -2
View File
@@ -422,7 +422,7 @@ export class SwingEngine {
: position.entryPrice * (1 + Math.max(0, this.config.stopLossPct)); : position.entryPrice * (1 + Math.max(0, this.config.stopLossPct));
const tick = Math.max(1e-9, this.config.priceTick); const tick = Math.max(1e-9, this.config.priceTick);
const lastPrice = referencePrice ?? Number(this.tickerSnapshot?.lastPrice) ?? null; const lastPrice = referencePrice;
// Kill-switch (always-on). // Kill-switch (always-on).
const triggerKill = const triggerKill =
@@ -621,4 +621,3 @@ export class SwingEngine {
}); });
} }
} }
+1 -1
View File
@@ -386,7 +386,7 @@ export class TrendEngine {
private async enforceRateLimitStop(): Promise<void> { private async enforceRateLimitStop(): Promise<void> {
const position = getPosition(this.accountSnapshot, this.config.symbol); const position = getPosition(this.accountSnapshot, this.config.symbol);
if (Math.abs(position.positionAmt) < 1e-5) return; if (Math.abs(position.positionAmt) < 1e-5) return;
const price = this.getReferencePrice() ?? Number(this.tickerSnapshot?.lastPrice) ?? this.lastPrice; const price = this.getReferencePrice();
if (!Number.isFinite(price) || price == null) return; if (!Number.isFinite(price) || price == null) return;
const result = await this.handlePositionManagement(position, Number(price)); const result = await this.handlePositionManagement(position, Number(price));
if (result.closed) { if (result.closed) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it } from "vitest";
import type { ExchangeAdapter } from "../src/exchanges/adapter"; import type { ExchangeAdapter } from "../src/exchanges/adapter";
import type { import type {
AsterAccountSnapshot, AsterAccountSnapshot,