|
|
@@ -768,11 +768,11 @@ async function setupWsOrderGateways(options: {
|
|
|
});
|
|
|
await gateway.connect();
|
|
|
adapterRegistry.get(entry.id).attachWsGateway(gateway);
|
|
|
- const fillsChannel = `fills.${address}`;
|
|
|
- const ordersChannel = `orders.${address}`;
|
|
|
- wsClient.subscribeAuthenticated(fillsChannel);
|
|
|
- wsClient.subscribeAuthenticated(ordersChannel);
|
|
|
- logger.info({ accountId: entry.id, fillsChannel, ordersChannel }, 'WS order gateway connected and subscribed to channels');
|
|
|
+ const tradesParams = { source: 'account_trades', account: address };
|
|
|
+ const ordersParams = { source: 'account_order_updates', account: address };
|
|
|
+ wsClient.subscribeAuthenticated('account_trades', tradesParams);
|
|
|
+ wsClient.subscribeAuthenticated('account_order_updates', ordersParams);
|
|
|
+ logger.info({ accountId: entry.id, tradesParams, ordersParams }, 'WS order gateway connected and subscribed to channels');
|
|
|
} catch (error) {
|
|
|
logger.error({ accountId: entry.id, error }, 'Failed to initialize WS order gateway');
|
|
|
throw error;
|
|
|
@@ -813,11 +813,12 @@ function handlePrivateMessage(
|
|
|
const channel = parsed?.channel;
|
|
|
if (typeof channel !== "string") return;
|
|
|
|
|
|
- if (channel.startsWith("fills.") && channel.endsWith(address)) {
|
|
|
+ if (channel === "account_trades" || (channel.startsWith("fills.") && channel.endsWith(address))) {
|
|
|
const payload = parsed.data;
|
|
|
const records = Array.isArray(payload) ? payload : [payload];
|
|
|
logger.info({ accountId, channel, recordCount: records.length }, 'Received fill message from WebSocket');
|
|
|
for (const record of records) {
|
|
|
+ if (record?.u && record.u !== address) continue;
|
|
|
const fill = mapFillPayload(record);
|
|
|
if (!fill) {
|
|
|
logger.warn({ accountId, record }, 'Failed to map fill payload');
|
|
|
@@ -831,11 +832,12 @@ function handlePrivateMessage(
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (channel.startsWith("orders.") && channel.endsWith(address)) {
|
|
|
+ if (channel === "account_order_updates" || (channel.startsWith("orders.") && channel.endsWith(address))) {
|
|
|
const payload = parsed.data;
|
|
|
const records = Array.isArray(payload) ? payload : [payload];
|
|
|
logger.info({ accountId, channel, recordCount: records.length }, 'Received order update message from WebSocket');
|
|
|
for (const record of records) {
|
|
|
+ if (record?.u && record.u !== address) continue;
|
|
|
const update = record ?? {};
|
|
|
logger.info({ accountId, orderUpdate: update }, 'Processing order update event');
|
|
|
routeOrder(accountId, update);
|
|
|
@@ -850,25 +852,34 @@ function handlePrivateMessage(
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ logger.debug({ accountId, channel, payload: parsed?.data ?? parsed }, 'Unhandled Pacifica WS message');
|
|
|
}
|
|
|
|
|
|
function mapFillPayload(data: any): Fill | undefined {
|
|
|
if (!data) return undefined;
|
|
|
- const orderId = data.order_id ?? data.orderId;
|
|
|
- const symbol = data.symbol;
|
|
|
- const rawSide = (data.side ?? data.direction ?? "").toString().toLowerCase();
|
|
|
- const side = rawSide === "bid" || rawSide === "buy" ? "buy" : rawSide === "ask" || rawSide === "sell" ? "sell" : undefined;
|
|
|
- const price = Number(data.price ?? data.px);
|
|
|
- const sizeRaw = Number(data.size ?? data.amount);
|
|
|
+ const orderId = data.order_id ?? data.orderId ?? data.i ?? data.orderId;
|
|
|
+ const symbol = data.symbol ?? data.s;
|
|
|
+ const rawSideInput = (data.side ?? data.direction ?? data.d ?? data.ts ?? '').toString().toLowerCase();
|
|
|
+ let side: 'buy' | 'sell' | undefined;
|
|
|
+ if (rawSideInput === 'bid' || rawSideInput === 'buy' || rawSideInput.includes('long')) {
|
|
|
+ side = 'buy';
|
|
|
+ } else if (rawSideInput === 'ask' || rawSideInput === 'sell' || rawSideInput.includes('short')) {
|
|
|
+ side = 'sell';
|
|
|
+ }
|
|
|
+ const price = Number(data.price ?? data.px ?? data.p);
|
|
|
+ const sizeRaw = Number(data.size ?? data.sz ?? data.amount ?? data.a);
|
|
|
if (!orderId || !symbol || !side || !Number.isFinite(price) || !Number.isFinite(sizeRaw)) {
|
|
|
return undefined;
|
|
|
}
|
|
|
const size = Math.abs(sizeRaw);
|
|
|
- const fee = data.fee !== undefined ? Number(data.fee) : 0;
|
|
|
- const liquidityRaw = (data.liquidity ?? '').toString().toLowerCase();
|
|
|
- const liquidity = liquidityRaw === 'taker' ? 'taker' : 'maker';
|
|
|
- const tradeId = String(data.trade_id ?? data.tradeId ?? `${orderId}-${Date.now()}`);
|
|
|
- const tsValue = data.ts !== undefined ? Number(data.ts) : Date.now();
|
|
|
+ const fee = data.fee !== undefined ? Number(data.fee) : data.f !== undefined ? Number(data.f) : 0;
|
|
|
+ const liquidityRaw = (data.liquidity ?? data.te ?? '').toString().toLowerCase();
|
|
|
+ const liquidity = liquidityRaw.includes('taker') ? 'taker' : 'maker';
|
|
|
+ const tradeId = String(data.trade_id ?? data.tradeId ?? data.h ?? `${orderId}-${Date.now()}`);
|
|
|
+ const tsValue = data.ts !== undefined && Number.isFinite(Number(data.ts)) ? Number(data.ts)
|
|
|
+ : data.t !== undefined ? Number(data.t)
|
|
|
+ : Date.now();
|
|
|
const ts = Number.isFinite(tsValue) ? tsValue : Date.now();
|
|
|
return {
|
|
|
orderId: String(orderId),
|