import {test} from 'node:test' import assert from 'node:assert' import {getClientForAddress, getPositionHistoryImpl} from '../../src/plugins/custom/gmx.js' test('GMX get position history - Closed positions with actual PnL', async (t) => { await t.test('should get closed positions with actual GMX PnL data', async () => { const sdk = await getClientForAddress('0x8767F195D1a3103789230aaaE9c0E0825a9802c6') const result = await getPositionHistoryImpl( sdk, 0, // pageIndex 500 // pageSize ) console.log('\nšŸ“Š Closed Positions Summary:') console.log(`Total closed positions: ${result.length}`) if (result.length > 0) { console.log('\nšŸ’° PnL Details:') result.forEach((position: any, index) => { console.log(`\n--- Position ${index + 1} ---`) console.log(`Ticker: ${position.ticker}`) console.log(`Direction: ${position.direction}`) console.log(`Close Price: $${position.price?.toFixed(2) || 'N/A'}`) console.log(`Quantity: ${position.quantity?.toFixed(4) || 'N/A'}`) console.log(`Leverage: ${position.leverage}x`) console.log(`Status: ${position.status}`) console.log(`PnL After Fees: $${position.pnl?.toFixed(2) || 'N/A'}`) console.log(`UI Fees: $${position.UiFees?.toFixed(2) || 'N/A'}`) console.log(`Gas Fees: $${position.GasFees?.toFixed(2) || 'N/A'}`) if (position.ProfitAndLoss) { console.log(`Realized PnL: $${position.ProfitAndLoss.realized?.toFixed(2) || 'N/A'}`) console.log(`Net PnL: $${position.ProfitAndLoss.net?.toFixed(2) || 'N/A'}`) } // Verify critical data for reconciliation assert.ok(position.ProfitAndLoss, 'Position should have ProfitAndLoss data') assert.ok(typeof position.ProfitAndLoss.realized === 'number', 'Realized PnL should be a number') assert.ok(typeof position.pnl === 'number', 'Position pnl should be a number') }) // Calculate total PnL const totalPnL = result.reduce((sum: number, pos: any) => sum + (pos.pnl || 0), 0) console.log(`\nšŸ’µ Total PnL from all closed positions: $${totalPnL.toFixed(2)}`) } assert.ok(result, 'Position history result should be defined') assert.ok(Array.isArray(result), 'Position history should be an array') }) await t.test('should get closed positions with date range', async () => { const sdk = await getClientForAddress('0x8767F195D1a3103789230aaaE9c0E0825a9802c6') // Get positions from the last 1 hour const toDate = new Date() const fromDate = new Date(toDate.getTime() - (60 * 60 * 1000)) // 1 hour ago const fromDateTime = fromDate.toISOString() const toDateTime = toDate.toISOString() const result = await getPositionHistoryImpl( sdk, 0, 10, undefined, // ticker fromDateTime, toDateTime ) console.log(`\nšŸ“… Closed positions in last 1 hour: ${result.length}`) console.log(`From: ${fromDateTime}`) console.log(`To: ${toDateTime}`) // Verify all positions are within date range result.forEach(position => { const positionDate = new Date(position.date) console.log(`Position date: ${positionDate.toISOString()}`) const isInRange = positionDate >= fromDate && positionDate <= toDate // Note: This assertion might fail if GMX returns positions outside the range // In that case, GMX API might not support the filtering properly if (!isInRange) { console.warn(`āš ļø Position date ${positionDate.toISOString()} is outside requested range`) } }) assert.ok(result, 'Position history result should be defined') assert.ok(Array.isArray(result), 'Position history should be an array') }) await t.test('should verify PnL data is suitable for reconciliation', async () => { const sdk = await getClientForAddress('0x8767F195D1a3103789230aaaE9c0E0825a9802c6') const result = await getPositionHistoryImpl(sdk, 0, 5) console.log('\nšŸ” Reconciliation Data Verification:') result.forEach((position: any, index) => { console.log(`\nPosition ${index + 1}:`) console.log(` Has ProfitAndLoss: ${!!position.ProfitAndLoss}`) console.log(` Has realized PnL: ${typeof position.ProfitAndLoss?.realized === 'number'}`) console.log(` Realized value: ${position.ProfitAndLoss?.realized}`) console.log(` Has fees: UI=${position.UiFees}, Gas=${position.GasFees}`) // These are the critical fields needed for HandleClosedPosition reconciliation assert.ok(position.ProfitAndLoss, 'Must have ProfitAndLoss for reconciliation') assert.ok( typeof position.ProfitAndLoss.realized === 'number', 'Must have numeric realized PnL for reconciliation' ) assert.ok(position.status === 'Finished', 'Position should be finished') }) }) })