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 start # 等价于运行 index.ts
bun run dev # 调试模式
bun run lint # 执行 Oxlint 检查
bun run lint:fix # 自动修复可安全修复的问题
bun x vitest run # 执行全部测试
```
@@ -292,6 +294,8 @@ bun run pm2:start:offset
## 测试
项目使用 Vitest
```bash
bun run lint
bun run lint:fix
bun run test
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 start # Alias for bun run index.ts
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
```
@@ -288,6 +290,8 @@ Run `pm2 save` afterwards if you want the process list to survive reboots.
## Testing
Powered by Vitest:
```bash
bun run lint
bun run lint:fix
bun run test
bun x vitest --watch
```
+41
View File
@@ -21,6 +21,7 @@
},
"devDependencies": {
"@types/bun": "^1.3.9",
"oxlint": "^1.54.0",
"vitest": "^4.0.18",
},
"peerDependencies": {
@@ -107,6 +108,44 @@
"@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-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=="],
"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=="],
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
+3
View File
@@ -14,6 +14,8 @@
"scripts": {
"dev": "bun run index.ts",
"start": "bun run index.ts",
"lint": "oxlint",
"lint:fix": "oxlint --fix",
"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:watch": "bun x vitest",
@@ -27,6 +29,7 @@
},
"devDependencies": {
"@types/bun": "^1.3.9",
"oxlint": "^1.54.0",
"vitest": "^4.0.18"
},
"peerDependencies": {
+1 -1
View File
@@ -155,7 +155,7 @@ function parseExchangeCommand(
options: Record<string, string | boolean>,
common: CommandCommonOptions & { help?: boolean }
): 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 === "capabilities") return { kind: "exchange-capabilities", ...common };
throw new CommandParseError(`Unsupported exchange action '${action}'`);
+6 -6
View File
@@ -543,7 +543,7 @@ export class AsterSpotRestClient {
}
try {
return JSON.parse(text) as T;
} catch (error) {
} catch {
throw new Error(`[AsterSpotRestClient] 无法解析响应: ${text.slice(0, 200)}`);
}
}
@@ -795,7 +795,7 @@ export class AsterRestClient {
}
try {
return JSON.parse(text) as AsterFuturesExchangeInfo;
} catch (error) {
} catch {
throw new Error(`[AsterRestClient] 无法解析交易规则响应: ${text.slice(0, 200)}`);
}
}
@@ -869,7 +869,7 @@ export class AsterRestClient {
try {
const payload = JSON.parse(text) as any[];
return payload.map((entry) => fromRestKline(entry, interval, upper));
} catch (error) {
} catch {
throw new Error(`[AsterRestClient] 无法解析K线响应: ${text.slice(0, 200)}`);
}
}
@@ -899,7 +899,7 @@ export class AsterRestClient {
const payload = JSON.parse(text) as any;
// The response shape mirrors Binance: { symbol, markPrice, indexPrice, lastFundingRate, nextFundingTime, time }
return payload;
} catch (error) {
} catch {
throw new Error(`[AsterRestClient] 无法解析资金费率响应: ${text.slice(0, 200)}`);
}
}
@@ -942,7 +942,7 @@ export class AsterRestClient {
}
try {
return JSON.parse(text) as T;
} catch (error) {
} catch {
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.initializing) return this.initializing;
this.initializing = (async () => {
+12 -17
View File
@@ -7,7 +7,6 @@ import ccxt, {
import NodeWebSocket from "ws";
import { sign, utils as edUtils, hashes as edHashes } from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512";
import { randomBytes } from "crypto";
import type {
AsterAccountSnapshot,
AsterAccountPosition,
@@ -137,17 +136,16 @@ export class BackpackGateway {
}
private async doInitialize(symbol?: string): Promise<void> {
try {
await this.exchange.loadMarkets();
const requested = (symbol ?? this.symbol).toUpperCase();
const market = this.findMarket(requested);
if (!market) {
throw new Error(`Symbol ${requested} not found in Backpack markets`);
}
this.market = market;
this.marketSymbol = market.symbol;
this.marketId = market.id;
this.isContractMarket = Boolean(market.contract);
await this.exchange.loadMarkets();
const requested = (symbol ?? this.symbol).toUpperCase();
const market = this.findMarket(requested);
if (!market) {
throw new Error(`Symbol ${requested} not found in Backpack markets`);
}
this.market = market;
this.marketSymbol = market.symbol;
this.marketId = market.id;
this.isContractMarket = Boolean(market.contract);
if (process.env.BACKPACK_DEBUG === "1") {
console.debug("[BackpackGateway] marketInfo", {
userSymbol: this.symbol,
@@ -155,10 +153,7 @@ export class BackpackGateway {
marketId: this.marketId,
});
}
this.initialized = true;
} catch (error) {
throw error;
}
this.initialized = true;
}
private findMarket(requested: string): any | null {
@@ -774,7 +769,7 @@ export class BackpackGateway {
void this.resubscribeAllTopics();
};
private handleWsClose = (event: any): void => {
private handleWsClose = (_event: any): void => {
if (this.wsCleanup) {
try {
this.wsCleanup();
-3
View File
@@ -1,9 +1,6 @@
import ccxt, {
type Balances,
type Order as CcxtOrder,
type OrderBook as CcxtOrderBook,
type OHLCV as CcxtOhlcv,
type Ticker as CcxtTicker,
} from "ccxt";
import axios from "axios";
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) => ({
openTime: nsToMs(entry.open_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,
CreateOrderParams,
} from "../types";
import { extractMessage } from "../../utils/errors";
import type { OrderSide, OrderType } from "../types";
import { LighterHttpClient } from "./http-client";
import { HttpNonceManager } from "./nonce-manager";
import { LighterSigner, type CreateOrderSignParams } from "./signer";
import { bytesToHex } from "./bytes";
import type {
LighterAccountDetails,
LighterAccountAsset,
@@ -39,7 +37,6 @@ import {
LIGHTER_HOSTS,
LIGHTER_ORDER_TYPE,
LIGHTER_TIME_IN_FORCE,
DEFAULT_ORDER_EXPIRY_PLACEHOLDER,
IMMEDIATE_OR_CANCEL_EXPIRY_PLACEHOLDER,
type LighterEnvironment,
} from "./constants";
@@ -2210,7 +2207,7 @@ function extractJsonRequestId(message: any): string | null {
function tryParseTxInfo(value: string): unknown {
try {
return JSON.parse(value);
} catch (_) {
} catch {
return value;
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ function computeExecutedQty(order: LighterOrder): string {
if (Number.isFinite(initial) && Number.isFinite(remaining)) {
return (initial - remaining).toString();
}
} catch (_) {
} catch {
// fall through
}
}
+1 -1
View File
@@ -1684,7 +1684,7 @@ export class NadoGateway {
try {
const text = typeof data === "string" ? data : data.toString("utf8");
message = JSON.parse(text);
} catch (_error) {
} catch {
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
const mod = require("ccxt.pro");
return mod?.default ?? mod;
} catch (_error) {
} catch {
return null;
}
}
@@ -571,7 +571,6 @@ export class ParadexGateway {
const market = typeof (this.exchange as any).market === "function"
? (this.exchange as any).market(symbol)
: (this.exchange.markets ?? {})[symbol];
const precisionDigits = Number((market?.precision?.amount ?? market?.amountPrecision));
const limitMin = Number(market?.limits?.amount?.min);
// Only trust explicit exchange min limit; do NOT infer 1 from precision=0
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))) {
amount = Number((this.exchange as any).amountToPrecision(symbol, amount));
}
} catch (_normalizeError) {
} catch {
// 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>();
for (const order of open) {
-1
View File
@@ -4,7 +4,6 @@ import { App } from "./ui/App";
import { setupGlobalErrorHandlers } from "./runtime-errors";
import { parseCliArgs, printCliHelp } from "./cli/args";
import { startStrategy } from "./cli/strategy-runner";
import { resolveExchangeId } from "./exchanges/create-adapter";
import { CommandParseError, parseCommandArgv, printCommandHelp } from "./cli/command-parser";
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 (Math.abs(wallet) === 0 && Math.abs(available) === 0) continue;
const isTaggedFuturesAsset = /0$/.test(name);
const isTaggedFuturesAsset = name.endsWith("0");
if (isTaggedFuturesAsset) {
futuresBalances.push({ asset: name.replace(/0$/, ""), wallet, available });
continue;
+1 -1
View File
@@ -461,7 +461,7 @@ export class GridEngine {
return false;
}
private async haltGrid(price: number): Promise<void> {
private async haltGrid(_price: number): Promise<void> {
if (!this.running) return;
const reason = this.stopReason ?? "触发网格止损";
this.log("warn", `${reason},开始执行平仓与撤单`);
-1
View File
@@ -3,7 +3,6 @@ import type { ExchangeAdapter } from "../exchanges/adapter";
import type {
AsterAccountSnapshot,
AsterDepth,
AsterKline,
AsterOrder,
AsterTicker,
} from "../exchanges/types";
+1 -2
View File
@@ -422,7 +422,7 @@ export class SwingEngine {
: position.entryPrice * (1 + Math.max(0, this.config.stopLossPct));
const tick = Math.max(1e-9, this.config.priceTick);
const lastPrice = referencePrice ?? Number(this.tickerSnapshot?.lastPrice) ?? null;
const lastPrice = referencePrice;
// Kill-switch (always-on).
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> {
const position = getPosition(this.accountSnapshot, this.config.symbol);
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;
const result = await this.handlePositionManagement(position, Number(price));
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 {
AsterAccountSnapshot,