Fix broker trade dedupe on financial corrections#197
Conversation
Co-authored-by: Hugo Demenez <hugodemenez@users.noreply.github.com>
Co-authored-by: Hugo Demenez <hugodemenez@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🤖 Automated Code ReviewPR Review SummaryThis PR fixes broker trade re-import behavior: financial corrections no longer mint new rows, user annotations are preserved on update, and persistence logic is extracted into a tested module. The direction is sound and the core design is reasonable. What works well
Critical / high-priority issues1. Updates are excluded from the returned count: return {
error: result.count === 0 && tradesToUpdate.length === 0 ? 'NO_TRADES_ADDED' : false,
numberOfTradesAdded: result.countA re-sync that only updates existing trades reports 2. Tests are not wired into the project
Medium issues3. Over-broad The lookup uses independent const existingBrokerTrades = await prisma.trade.findMany({
where: {
userId,
accountNumber: { in: candidateAccountNumbers },
entryId: { in: candidateEntryIds },
closeId: { in: candidateCloseIds },
},This matches the Cartesian product of those sets, not specific 4. Legacy duplicate broker rows If duplicate rows already exist for the same broker key (from the old UUID behavior), 5. Normalization mismatch between DB lookup and key generation
6. Large update transactions All updates run in a single Minor / style
SecurityNo major concerns. Queries are scoped by VerdictApprove with changes recommended. The main functional gap is underreporting updated trades in the API response. Wire up Vitest before relying on the new tests. The broad Suggested test plan before merge:
Generated by Cursor CLI workflow — |
Bug and impact
DxFeed's recent PnL mapping correction changed the
pnlandcommissionvalues used bysaveTradesActionwhen generating deterministic trade IDs. A user who re-synced the same DxFeed history after that change could insert duplicate trades instead of hittingskipDuplicates, double-counting PnL, fees, win rate, and trade counts. Existing imported rows with older financial semantics would also remain stale on re-sync.Root cause
saveTradesActionregenerated IDs from financial fields (pnlandcommission) even for broker-synced trades that have stable externalentryId/closeIdvalues. When those financial fields changed, the same logical broker trade got a different primary key.Fix
lib/trade-persistence.ts.pnl/commissionfrom generated IDs only when stable broker entry/close IDs exist; generic/manual imports keep those fields in the signature to preserve uniqueness.entryId/closeId/account key and update broker-derived fields instead of inserting a duplicate.vitestdev dependency.Validation
npx vitest run lib/trade-persistence.test.ts lib/dxfeed-token.test.tspassed: 2 files, 7 tests.DIRECT_URL="postgresql://user:pass@localhost:5432/db" DATABASE_URL="postgresql://user:pass@localhost:5432/db" npx prisma generate && npm run typecheckpassed after generating local Prisma types.npx eslint lib/trade-persistence.ts lib/trade-persistence.test.tspassed.npx eslint server/database.ts lib/trade-persistence.ts lib/trade-persistence.test.tsremains blocked by pre-existing unrelated lint errors inserver/database.ts(no-explicit-anyand unused variable locations outside this change).