From fbcaac95f5706dc18d1f0f07d15bf9be34588091 Mon Sep 17 00:00:00 2001 From: Ramiro Paz Date: Fri, 13 Mar 2026 11:35:37 -0300 Subject: [PATCH] fixes in quotes --- src/client/api/rest/controller.go | 5 ++- src/client/api/rest/model.go | 29 ++++--------- src/client/fix/manager.go | 67 ++++++++++++++++++++++++------- src/domain/order.go | 7 +++- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/client/api/rest/controller.go b/src/client/api/rest/controller.go index cc53088..f739218 100644 --- a/src/client/api/rest/controller.go +++ b/src/client/api/rest/controller.go @@ -325,14 +325,15 @@ func (cont *Controller) SendQuote(ctx *gin.Context) { return } - bidPx, offerPx, bidSize, offerSize, err := req.toDecimals() + bidPx, offerPx, _, _, err := req.toDecimals() if err != nil { ctx.JSON(http.StatusBadRequest, HTTPError{Error: err.Error()}) return } - if err = cont.fixSender.SendQuote(req.ClOrdID, req.QuoteID, req.Symbol, req.Currency, bidPx, offerPx, bidSize, offerSize); err != nil { + if err = cont.fixSender.SendQuote( + req.ClOrdID, req.QuoteID, req.Symbol, req.SecurityIDSource, req.Currency, bidPx, offerPx); err != nil { ctx.JSON(http.StatusInternalServerError, HTTPError{Error: err.Error()}) return diff --git a/src/client/api/rest/model.go b/src/client/api/rest/model.go index e7cfb9c..35d4316 100644 --- a/src/client/api/rest/model.go +++ b/src/client/api/rest/model.go @@ -24,14 +24,13 @@ type Session struct { } type QuoteRequest struct { - ClOrdID string `json:"cl_ord_id" binding:"required"` - QuoteID string `json:"quote_id" binding:"required"` - Symbol string `json:"symbol" binding:"required"` - Currency string `json:"currency"` - BidPx string `json:"bid_px" binding:"required"` - OfferPx string `json:"offer_px" binding:"required"` - BidSize string `json:"bid_size"` - OfferSize string `json:"offer_size"` + ClOrdID string `json:"cl_ord_id" binding:"required"` + QuoteID string `json:"quote_id" binding:"required"` + Symbol string `json:"symbol" binding:"required"` + Currency string `json:"currency"` + BidPx string `json:"bid_px" binding:"required"` + OfferPx string `json:"offer_px" binding:"required"` + SecurityIDSource string `json:"security_id_source" binding:"required"` } func (r QuoteRequest) toDecimals() (bidPx, offerPx, bidSize, offerSize decimal.Decimal, err error) { @@ -45,19 +44,5 @@ func (r QuoteRequest) toDecimals() (bidPx, offerPx, bidSize, offerSize decimal.D return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid offer_px: %w", err) } - if r.BidSize != "" { - bidSize, err = decimal.NewFromString(r.BidSize) - if err != nil { - return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid bid_size: %w", err) - } - } - - if r.OfferSize != "" { - offerSize, err = decimal.NewFromString(r.OfferSize) - if err != nil { - return bidPx, offerPx, bidSize, offerSize, fmt.Errorf("invalid offer_size: %w", err) - } - } - return bidPx, offerPx, bidSize, offerSize, nil } diff --git a/src/client/fix/manager.go b/src/client/fix/manager.go index 646ad40..9278d95 100644 --- a/src/client/fix/manager.go +++ b/src/client/fix/manager.go @@ -115,7 +115,12 @@ func (m *Manager) onLogout(sessionID quickfix.SessionID) { } // SendQuote implements domain.FIXSender. -func (m *Manager) SendQuote(clOrdID, quoteID, symbol, currency string, bidPx, offerPx, bidSize, offerSize decimal.Decimal) error { +func (m *Manager) SendQuote( + clOrdID, quoteID, symbol string, + secIDSource string, + currency string, + bidPx, offerPx decimal.Decimal, +) error { m.sessionsMu.RLock() var sessionID quickfix.SessionID var ok bool @@ -134,28 +139,34 @@ func (m *Manager) SendQuote(clOrdID, quoteID, symbol, currency string, bidPx, of } q := quote.New( - field.NewQuoteID(quoteID), + field.NewQuoteID("NONREF"), field.NewQuoteType(enum.QuoteType_INDICATIVE), field.NewTransactTime(time.Now()), ) - q.SetSymbol(symbol) + sIDSource := enum.SecurityIDSource_ISIN_NUMBER + if secIDSource == "1" { + sIDSource = enum.SecurityIDSource_CUSIP + } + + q.SetSymbol("[N/A]") + q.SetSecurityID(symbol) + q.SetSecurityIDSource(sIDSource) q.SetQuoteID(quoteID) if currency != "" { q.SetCurrency(currency) } - q.SetBidPx(bidPx, 8) - q.SetOfferPx(offerPx, 8) - - if !bidSize.IsZero() { - q.SetBidSize(bidSize, 8) + if !bidPx.IsZero() { + q.SetBidPx(bidPx, 8) + q.SetSide(enum.Side_SELL) + } else { + q.SetOfferPx(offerPx, 8) + q.SetSide(enum.Side_BUY) } - if !offerSize.IsZero() { - q.SetOfferSize(offerSize, 8) - } + q.SetPriceType(enum.PriceType_PERCENTAGE) if err := quickfix.SendToTarget(q, sessionID); err != nil { err = tracerr.Errorf("error sending FIX quote: %s", err) @@ -177,18 +188,46 @@ func (m *Manager) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID qu return } - var symbol, currency string + var ( + symbol, currency string + side enum.Side + secIDSource enum.SecurityIDSource + ) relatedSyms, relErr := msg.GetNoRelatedSym() if relErr == nil && relatedSyms.Len() > 0 { sym := relatedSyms.Get(0) - symbol, _ = sym.GetSymbol() + symbol, _ = sym.GetSecurityID() + secIDSource, _ = sym.GetSecurityIDSource() currency, _ = sym.GetCurrency() + side, _ = sym.GetSide() } price := decimal.NewFromFloat(99.6) + bidPx, offerPx := decimal.Zero, decimal.Zero - if sendErr := m.SendQuote(quoteReqID, quoteReqID, symbol, currency, price, price, decimal.Zero, decimal.Zero); sendErr != nil { + if side == enum.Side_BUY { + offerPx = price + } else { + bidPx = price + } + + var sIDSource string + if secIDSource == enum.SecurityIDSource_ISIN_NUMBER { + sIDSource = "4" + } else { + sIDSource = "1" + } + + if sendErr := m.SendQuote( + quoteReqID, + quoteReqID, + symbol, + sIDSource, + currency, + bidPx, + offerPx, + ); sendErr != nil { slog.Error("handleQuoteRequest: failed to send quote", "quoteReqID", quoteReqID, "error", sendErr.Error()) } } diff --git a/src/domain/order.go b/src/domain/order.go index c386727..e7f677c 100644 --- a/src/domain/order.go +++ b/src/domain/order.go @@ -28,5 +28,10 @@ type OrderStore interface { // FIXSender is the port for sending FIX messages back to clients. type FIXSender interface { - SendQuote(clOrdID, quoteID, symbol, currency string, bidPx, offerPx, bidSize, offerSize decimal.Decimal) error + SendQuote( + clOrdID, quoteID, symbol string, + secIDSource string, + currency string, + bidPx, offerPx decimal.Decimal, + ) error }