mirror of
https://github.com/discountry/ritmex-bot.git
synced 2026-09-11 17:28:08 +00:00
Update API token creation date in documentation and configuration
- Revised the `.env.example` and `maker-points-guide.md` to reflect the updated token creation date from 2025-01-15 to 2026-01-15. - Enhanced the `order-coordinator.ts`, `order-schema.ts`, and `types.ts` files to support stop-loss and take-profit price parameters in order intents. - Updated the `StandxGateway` and `order.ts` to handle new stop-loss and take-profit parameters in order creation. - Improved the `MakerPointsEngine` to calculate stop-loss prices based on order type, enhancing order management capabilities.
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ STANDX_SYMBOL=BTC-USD
|
|||||||
# STANDX_REQUEST_PRIVATE_KEY=
|
# STANDX_REQUEST_PRIVATE_KEY=
|
||||||
# Token expiry configuration (recommended method: creation date + validity days)
|
# Token expiry configuration (recommended method: creation date + validity days)
|
||||||
# Get these values when generating API token at https://standx.com/user/session
|
# Get these values when generating API token at https://standx.com/user/session
|
||||||
# STANDX_TOKEN_CREATE_DATE=2025-01-15 # Token creation date (YYYY-MM-DD format)
|
# STANDX_TOKEN_CREATE_DATE=2026-01-15 # Token creation date (YYYY-MM-DD format)
|
||||||
# STANDX_TOKEN_VALIDITY_DAYS=30 # Token validity period in days
|
# STANDX_TOKEN_VALIDITY_DAYS=30 # Token validity period in days
|
||||||
# Legacy method: direct expiry timestamp (Unix seconds)
|
# Legacy method: direct expiry timestamp (Unix seconds)
|
||||||
# STANDX_TOKEN_EXPIRY=1737092800
|
# STANDX_TOKEN_EXPIRY=1737092800
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ https://standx.com/user/session
|
|||||||
你会看到类似这样的信息:
|
你会看到类似这样的信息:
|
||||||
- **Token**(很长一串以 eyJ 开头的字符串)
|
- **Token**(很长一串以 eyJ 开头的字符串)
|
||||||
- **Ed25519 Private Key**(Base58 格式的私钥,类似 `HdsyJD7oWgT756124j3taSPGv...`)
|
- **Ed25519 Private Key**(Base58 格式的私钥,类似 `HdsyJD7oWgT756124j3taSPGv...`)
|
||||||
- **创建日期**(例如:2025-01-15)
|
- **创建日期**(例如:2026-01-15)
|
||||||
- **有效期天数**(例如:30 天)
|
- **有效期天数**(例如:30 天)
|
||||||
|
|
||||||
> 🔴 **请把这些值复制保存下来!**
|
> 🔴 **请把这些值复制保存下来!**
|
||||||
@@ -140,8 +140,8 @@ MAKER_POINTS_BAND_30_100=true
|
|||||||
|
|
||||||
# ===== Token 过期时间配置(推荐配置) =====
|
# ===== Token 过期时间配置(推荐配置) =====
|
||||||
# 填写你创建 API Token 时显示的创建日期和有效期天数
|
# 填写你创建 API Token 时显示的创建日期和有效期天数
|
||||||
# 创建日期格式:YYYY-MM-DD(例如:2025-01-15)
|
# 创建日期格式:YYYY-MM-DD(例如:2026-01-15)
|
||||||
STANDX_TOKEN_CREATE_DATE=2025-01-15
|
STANDX_TOKEN_CREATE_DATE=2026-01-15
|
||||||
# 有效期天数(例如:30)
|
# 有效期天数(例如:30)
|
||||||
STANDX_TOKEN_VALIDITY_DAYS=30
|
STANDX_TOKEN_VALIDITY_DAYS=30
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ STANDX_TOKEN_VALIDITY_DAYS=30
|
|||||||
假设你生成的 API Token 信息是:
|
假设你生成的 API Token 信息是:
|
||||||
- Token: `eyJhbGciOiJFUzI1NiIsImtpZCI6IlhnaEJQSVNuN0RQVHlMcWJtLUVHVkVhOU1lMFpwdU9iMk1Qc2gtbUFlencifQ...`
|
- Token: `eyJhbGciOiJFUzI1NiIsImtpZCI6IlhnaEJQSVNuN0RQVHlMcWJtLUVHVkVhOU1lMFpwdU9iMk1Qc2gtbUFlencifQ...`
|
||||||
- Ed25519 Private Key: `HdsyJD7oWgT756124j3taSPGv17vo5u7FafDq3vrun4f`
|
- Ed25519 Private Key: `HdsyJD7oWgT756124j3taSPGv17vo5u7FafDq3vrun4f`
|
||||||
- 创建日期: `2025-01-15`
|
- 创建日期: `2026-01-15`
|
||||||
- 有效期: `30` 天
|
- 有效期: `30` 天
|
||||||
|
|
||||||
那么你的 `.env` 应该这样写:
|
那么你的 `.env` 应该这样写:
|
||||||
@@ -176,7 +176,7 @@ MAKER_POINTS_MIN_REPRICE_BPS=3
|
|||||||
MAKER_POINTS_BAND_0_10=true
|
MAKER_POINTS_BAND_0_10=true
|
||||||
MAKER_POINTS_BAND_10_30=true
|
MAKER_POINTS_BAND_10_30=true
|
||||||
MAKER_POINTS_BAND_30_100=true
|
MAKER_POINTS_BAND_30_100=true
|
||||||
STANDX_TOKEN_CREATE_DATE=2025-01-15
|
STANDX_TOKEN_CREATE_DATE=2026-01-15
|
||||||
STANDX_TOKEN_VALIDITY_DAYS=30
|
STANDX_TOKEN_VALIDITY_DAYS=30
|
||||||
# TELEGRAM_BOT_TOKEN=你的BotToken
|
# TELEGRAM_BOT_TOKEN=你的BotToken
|
||||||
# TELEGRAM_CHAT_ID=你的ChatID
|
# TELEGRAM_CHAT_ID=你的ChatID
|
||||||
@@ -237,13 +237,13 @@ bun run pm2:start:maker-points
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 创建日期(格式:YYYY-MM-DD)
|
# 创建日期(格式:YYYY-MM-DD)
|
||||||
STANDX_TOKEN_CREATE_DATE=2025-01-15
|
STANDX_TOKEN_CREATE_DATE=2026-01-15
|
||||||
# 有效期天数
|
# 有效期天数
|
||||||
STANDX_TOKEN_VALIDITY_DAYS=30
|
STANDX_TOKEN_VALIDITY_DAYS=30
|
||||||
```
|
```
|
||||||
|
|
||||||
**示例计算:**
|
**示例计算:**
|
||||||
- 创建日期:2025-01-15
|
- 创建日期:2026-01-15
|
||||||
- 有效期:30 天
|
- 有效期:30 天
|
||||||
- 过期时间:2025-02-14 00:00:00 UTC
|
- 过期时间:2025-02-14 00:00:00 UTC
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ type PlaceOrderOptions = {
|
|||||||
priceTick: number;
|
priceTick: number;
|
||||||
qtyStep: number;
|
qtyStep: number;
|
||||||
skipDedupe?: boolean;
|
skipDedupe?: boolean;
|
||||||
|
slPrice?: number;
|
||||||
|
tpPrice?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function placeOrder(
|
export async function placeOrder(
|
||||||
@@ -176,9 +178,11 @@ export async function placeOrder(
|
|||||||
timeInForce: reduceOnly ? "GTC" : "GTX",
|
timeInForce: reduceOnly ? "GTC" : "GTX",
|
||||||
reduceOnly: reduceOnly ? true : undefined,
|
reduceOnly: reduceOnly ? true : undefined,
|
||||||
closePosition,
|
closePosition,
|
||||||
|
slPrice: opts?.slPrice,
|
||||||
|
tpPrice: opts?.tpPrice,
|
||||||
});
|
});
|
||||||
pendings[type] = String(order.orderId);
|
pendings[type] = String(order.orderId);
|
||||||
log("order", `挂限价单: ${side} @ ${priceNum} 数量 ${quantity} reduceOnly=${reduceOnly}`);
|
log("order", `挂限价单: ${side} @ ${priceNum} 数量 ${quantity} reduceOnly=${reduceOnly}${opts?.slPrice ? ` sl=${opts.slPrice}` : ""}`);
|
||||||
return order;
|
return order;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
unlockOperating(locks, timers, pendings, type);
|
unlockOperating(locks, timers, pendings, type);
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ export interface BaseOrderIntent {
|
|||||||
|
|
||||||
export interface LimitOrderIntent extends BaseOrderIntent {
|
export interface LimitOrderIntent extends BaseOrderIntent {
|
||||||
price: number;
|
price: number;
|
||||||
|
// StandX TPSL 参数
|
||||||
|
slPrice?: number; // 止损价格
|
||||||
|
tpPrice?: number; // 止盈价格
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MarketOrderIntent extends BaseOrderIntent {
|
export interface MarketOrderIntent extends BaseOrderIntent {
|
||||||
|
|||||||
@@ -799,6 +799,13 @@ export class StandxGateway {
|
|||||||
}
|
}
|
||||||
payload.price = price;
|
payload.price = price;
|
||||||
}
|
}
|
||||||
|
// StandX TPSL 参数
|
||||||
|
if (params.slPrice != null && Number.isFinite(params.slPrice)) {
|
||||||
|
payload.sl_price = toDecimalString(params.slPrice);
|
||||||
|
}
|
||||||
|
if (params.tpPrice != null && Number.isFinite(params.tpPrice)) {
|
||||||
|
payload.tp_price = toDecimalString(params.tpPrice);
|
||||||
|
}
|
||||||
const response = await this.requestJson<{ code?: number; message?: string; request_id?: string }>(
|
const response = await this.requestJson<{ code?: number; message?: string; request_id?: string }>(
|
||||||
"/api/new_order",
|
"/api/new_order",
|
||||||
{
|
{
|
||||||
@@ -863,6 +870,12 @@ export class StandxGateway {
|
|||||||
};
|
};
|
||||||
const handleError = (error: unknown) => {
|
const handleError = (error: unknown) => {
|
||||||
this.logger("marketWs", error);
|
this.logger("marketWs", error);
|
||||||
|
// 如果连接从未成功建立(握手失败),需要清理并重连
|
||||||
|
// 因为某些 WebSocket 实现在握手失败时可能不触发 close 事件
|
||||||
|
if (this.marketWs && !this.marketWsReady) {
|
||||||
|
this.marketWs = null;
|
||||||
|
this.scheduleReconnect();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if ("addEventListener" in this.marketWs && typeof this.marketWs.addEventListener === "function") {
|
if ("addEventListener" in this.marketWs && typeof this.marketWs.addEventListener === "function") {
|
||||||
@@ -886,8 +899,10 @@ export class StandxGateway {
|
|||||||
|
|
||||||
private scheduleReconnect(): void {
|
private scheduleReconnect(): void {
|
||||||
if (this.marketReconnectTimer) return;
|
if (this.marketReconnectTimer) return;
|
||||||
|
this.logDebug("scheduling reconnect in 2s");
|
||||||
this.marketReconnectTimer = setTimeout(() => {
|
this.marketReconnectTimer = setTimeout(() => {
|
||||||
this.marketReconnectTimer = null;
|
this.marketReconnectTimer = null;
|
||||||
|
this.logDebug("attempting reconnect");
|
||||||
this.connectMarketWs();
|
this.connectMarketWs();
|
||||||
}, WS_RECONNECT_DELAY);
|
}, WS_RECONNECT_DELAY);
|
||||||
}
|
}
|
||||||
@@ -1182,9 +1197,8 @@ export class StandxGateway {
|
|||||||
const order = this.mapOrder(raw);
|
const order = this.mapOrder(raw);
|
||||||
mergeOrderSnapshot(this.openOrders, order);
|
mergeOrderSnapshot(this.openOrders, order);
|
||||||
}
|
}
|
||||||
if (orders.length) {
|
// 无论是否有挂单都触发推送,确保上层状态更新
|
||||||
this.emitOrders();
|
this.emitOrders();
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger("openOrders", error);
|
this.logger("openOrders", error);
|
||||||
}
|
}
|
||||||
@@ -1509,6 +1523,33 @@ export class StandxGateway {
|
|||||||
// 停止断连保护重试
|
// 停止断连保护重试
|
||||||
this.stopDisconnectCancelRetry();
|
this.stopDisconnectCancelRetry();
|
||||||
|
|
||||||
|
// 清空本地挂单状态(重连后需要重新同步)
|
||||||
|
this.openOrders.clear();
|
||||||
|
|
||||||
|
// 主动触发一次数据推送,确保上层 feedStatus 能更新
|
||||||
|
this.emitOrders();
|
||||||
|
this.emitAccountSnapshot();
|
||||||
|
|
||||||
|
// 主动刷新账户和挂单数据
|
||||||
|
void this.refreshAccountSnapshot();
|
||||||
|
|
||||||
|
// 获取当前订阅的 symbols 并刷新数据
|
||||||
|
const subscribedSymbols = new Set<string>();
|
||||||
|
for (const key of this.subscriptions) {
|
||||||
|
const [, symbol] = key.split(":");
|
||||||
|
if (symbol) subscribedSymbols.add(symbol);
|
||||||
|
}
|
||||||
|
if (this.disconnectedSymbol) {
|
||||||
|
subscribedSymbols.add(this.disconnectedSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新每个 symbol 的数据
|
||||||
|
for (const symbol of subscribedSymbols) {
|
||||||
|
void this.refreshOpenOrders(symbol);
|
||||||
|
void this.fetchDepthSnapshot(symbol).catch((e) => this.logger("depthSnapshot", e));
|
||||||
|
void this.fetchTickerSnapshot(symbol).catch((e) => this.logger("tickerSnapshot", e));
|
||||||
|
}
|
||||||
|
|
||||||
// 触发重连事件
|
// 触发重连事件
|
||||||
for (const listener of this.connectionListeners) {
|
for (const listener of this.connectionListeners) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export async function createLimitOrder(intent: LimitOrderIntent): Promise<AsterO
|
|||||||
quantity: intent.quantity,
|
quantity: intent.quantity,
|
||||||
price: intent.price,
|
price: intent.price,
|
||||||
timeInForce: intent.timeInForce ?? "GTX",
|
timeInForce: intent.timeInForce ?? "GTX",
|
||||||
|
slPrice: intent.slPrice,
|
||||||
|
tpPrice: intent.tpPrice,
|
||||||
},
|
},
|
||||||
intent
|
intent
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export interface CreateOrderParams {
|
|||||||
reduceOnly?: StringBoolean;
|
reduceOnly?: StringBoolean;
|
||||||
closePosition?: StringBoolean;
|
closePosition?: StringBoolean;
|
||||||
triggerType?: "UNSPECIFIED" | "TAKE_PROFIT" | "STOP_LOSS";
|
triggerType?: "UNSPECIFIED" | "TAKE_PROFIT" | "STOP_LOSS";
|
||||||
|
// StandX TPSL 参数
|
||||||
|
slPrice?: number; // 止损价格
|
||||||
|
tpPrice?: number; // 止盈价格
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AsterAccountPosition {
|
export interface AsterAccountPosition {
|
||||||
|
|||||||
@@ -701,6 +701,9 @@ export class MakerPointsEngine {
|
|||||||
if (!target) continue;
|
if (!target) continue;
|
||||||
if (target.amount < EPS) continue;
|
if (target.amount < EPS) continue;
|
||||||
try {
|
try {
|
||||||
|
// 计算止损价格:买单在价格下方 $1,卖单在价格上方 $1
|
||||||
|
const priceNum = Number(target.price);
|
||||||
|
const slPrice = target.side === "BUY" ? priceNum - 1 : priceNum + 1;
|
||||||
await placeOrder(
|
await placeOrder(
|
||||||
this.exchange,
|
this.exchange,
|
||||||
this.config.symbol,
|
this.config.symbol,
|
||||||
@@ -718,6 +721,7 @@ export class MakerPointsEngine {
|
|||||||
priceTick: this.priceTick,
|
priceTick: this.priceTick,
|
||||||
qtyStep: this.qtyStep,
|
qtyStep: this.qtyStep,
|
||||||
skipDedupe: true,
|
skipDedupe: true,
|
||||||
|
slPrice,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user