-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Bug: Venue Position Calculation Returns Arbitrary OrderId
Description
The calculateVenuePositions() function aggregates positions by (venue, wallet) but returns map[OrderIdentifier]float64 where the OrderIdentifier includes an arbitrary OrderId field. This creates confusion because the OrderId in the result has no semantic meaning for position aggregation.
Location
filltracker/service.go:249-293
Current Behavior
func (s *Service) calculateVenuePositions(snapshot DealSnapshot) map[recomma.OrderIdentifier]float64 {
venuePositions := make(map[venueKey]float64)
venueIdentifiers := make(map[venueKey]recomma.OrderIdentifier)
for _, order := range snapshot.Orders {
key := venueKey{venue: order.Identifier.VenueID, wallet: order.Identifier.Wallet}
// Store arbitrary identifier (whichever order is processed last)
if _, exists := venueIdentifiers[key]; !exists {
venueIdentifiers[key] = order.Identifier // ⚠️ Arbitrary OrderId
}
// Calculate position...
}
// Return with arbitrary OrderId in the key
result := make(map[recomma.OrderIdentifier]float64)
for key, netQty := range venuePositions {
result[venueIdentifiers[key]] = netQty // OrderId is meaningless here
}
return result
}Expected Behavior
Position aggregation should either:
- Return
map[venueKey]float64to make it clear the key is(venue, wallet)only - Use a sentinel/zero
OrderIdto indicate it's not specific to any order - Document clearly that the
OrderIdfield is arbitrary and should be ignored
Impact
- Confusion: Callers might think the
OrderIdin the result is meaningful - Future Bugs: Someone might try to use the
OrderIdfrom the result map, leading to incorrect behavior - Type Safety: The type signature implies OrderId matters when it doesn't
Current Usage
The function is called from ReconcileTakeProfits():
venuePositions := s.calculateVenuePositions(snapshot)
for ident, venueNetQty := range venuePositions {
key := venueKey{venue: ident.VenueID, wallet: ident.Wallet} // Only uses venue+wallet
// ident.OrderId is ignored ✅
}The code works correctly because callers only extract venue and wallet, but this is fragile.
Suggested Fix
Option 1: Return Correct Type
func (s *Service) calculateVenuePositions(snapshot DealSnapshot) map[venueKey]float64 {
positions := make(map[venueKey]float64)
for _, order := range snapshot.Orders {
key := venueKey{venue: order.Identifier.VenueID, wallet: order.Identifier.Wallet}
if order.Side == "B" || strings.EqualFold(order.Side, "BUY") {
positions[key] += order.FilledQty
} else {
positions[key] -= order.FilledQty
}
}
return positions
}
// Update ReconcileTakeProfits to use venueKey directlyOption 2: Use Sentinel OrderId
func (s *Service) calculateVenuePositions(snapshot DealSnapshot) map[recomma.OrderIdentifier]float64 {
// ...
for key, netQty := range venuePositions {
// Use zero OrderId to indicate "not specific to any order"
ident := recomma.NewOrderIdentifier(
recomma.VenueID(key.venue),
key.wallet,
orderid.OrderId{}, // ✅ Explicit zero value
)
result[ident] = netQty
}
return result
}Option 3: Add Documentation
// calculateVenuePositions computes net filled quantity per (venue, wallet) pair.
//
// NOTE: The returned map keys include an OrderIdentifier, but the OrderId field
// is ARBITRARY and should be ignored. Only the VenueID and Wallet fields are
// meaningful for position aggregation. Callers should extract venue+wallet only.
func (s *Service) calculateVenuePositions(snapshot DealSnapshot) map[recomma.OrderIdentifier]float64 {
// ...
}Recommendation
Option 1 is cleanest - return the actual type being aggregated.
Branch
codex/investigate-multi-wallet-support-for-hyperliquid
Related
ReconcileTakeProfits()infilltracker/service.go:163venueKeytype definition infilltracker/service.go:240
Metadata
Metadata
Assignees
Labels
No labels