fixes in quotes
This commit is contained in:
@ -325,14 +325,15 @@ func (cont *Controller) SendQuote(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bidPx, offerPx, bidSize, offerSize, err := req.toDecimals()
|
bidPx, offerPx, _, _, err := req.toDecimals()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(http.StatusBadRequest, HTTPError{Error: err.Error()})
|
ctx.JSON(http.StatusBadRequest, HTTPError{Error: err.Error()})
|
||||||
|
|
||||||
return
|
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()})
|
ctx.JSON(http.StatusInternalServerError, HTTPError{Error: err.Error()})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@ -24,14 +24,13 @@ type Session struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QuoteRequest struct {
|
type QuoteRequest struct {
|
||||||
ClOrdID string `json:"cl_ord_id" binding:"required"`
|
ClOrdID string `json:"cl_ord_id" binding:"required"`
|
||||||
QuoteID string `json:"quote_id" binding:"required"`
|
QuoteID string `json:"quote_id" binding:"required"`
|
||||||
Symbol string `json:"symbol" binding:"required"`
|
Symbol string `json:"symbol" binding:"required"`
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
BidPx string `json:"bid_px" binding:"required"`
|
BidPx string `json:"bid_px" binding:"required"`
|
||||||
OfferPx string `json:"offer_px" binding:"required"`
|
OfferPx string `json:"offer_px" binding:"required"`
|
||||||
BidSize string `json:"bid_size"`
|
SecurityIDSource string `json:"security_id_source" binding:"required"`
|
||||||
OfferSize string `json:"offer_size"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r QuoteRequest) toDecimals() (bidPx, offerPx, bidSize, offerSize decimal.Decimal, err error) {
|
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)
|
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
|
return bidPx, offerPx, bidSize, offerSize, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,7 +115,12 @@ func (m *Manager) onLogout(sessionID quickfix.SessionID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendQuote implements domain.FIXSender.
|
// 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()
|
m.sessionsMu.RLock()
|
||||||
var sessionID quickfix.SessionID
|
var sessionID quickfix.SessionID
|
||||||
var ok bool
|
var ok bool
|
||||||
@ -134,28 +139,34 @@ func (m *Manager) SendQuote(clOrdID, quoteID, symbol, currency string, bidPx, of
|
|||||||
}
|
}
|
||||||
|
|
||||||
q := quote.New(
|
q := quote.New(
|
||||||
field.NewQuoteID(quoteID),
|
field.NewQuoteID("NONREF"),
|
||||||
field.NewQuoteType(enum.QuoteType_INDICATIVE),
|
field.NewQuoteType(enum.QuoteType_INDICATIVE),
|
||||||
field.NewTransactTime(time.Now()),
|
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)
|
q.SetQuoteID(quoteID)
|
||||||
|
|
||||||
if currency != "" {
|
if currency != "" {
|
||||||
q.SetCurrency(currency)
|
q.SetCurrency(currency)
|
||||||
}
|
}
|
||||||
|
|
||||||
q.SetBidPx(bidPx, 8)
|
if !bidPx.IsZero() {
|
||||||
q.SetOfferPx(offerPx, 8)
|
q.SetBidPx(bidPx, 8)
|
||||||
|
q.SetSide(enum.Side_SELL)
|
||||||
if !bidSize.IsZero() {
|
} else {
|
||||||
q.SetBidSize(bidSize, 8)
|
q.SetOfferPx(offerPx, 8)
|
||||||
|
q.SetSide(enum.Side_BUY)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !offerSize.IsZero() {
|
q.SetPriceType(enum.PriceType_PERCENTAGE)
|
||||||
q.SetOfferSize(offerSize, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quickfix.SendToTarget(q, sessionID); err != nil {
|
if err := quickfix.SendToTarget(q, sessionID); err != nil {
|
||||||
err = tracerr.Errorf("error sending FIX quote: %s", err)
|
err = tracerr.Errorf("error sending FIX quote: %s", err)
|
||||||
@ -177,18 +188,46 @@ func (m *Manager) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID qu
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var symbol, currency string
|
var (
|
||||||
|
symbol, currency string
|
||||||
|
side enum.Side
|
||||||
|
secIDSource enum.SecurityIDSource
|
||||||
|
)
|
||||||
|
|
||||||
relatedSyms, relErr := msg.GetNoRelatedSym()
|
relatedSyms, relErr := msg.GetNoRelatedSym()
|
||||||
if relErr == nil && relatedSyms.Len() > 0 {
|
if relErr == nil && relatedSyms.Len() > 0 {
|
||||||
sym := relatedSyms.Get(0)
|
sym := relatedSyms.Get(0)
|
||||||
symbol, _ = sym.GetSymbol()
|
symbol, _ = sym.GetSecurityID()
|
||||||
|
secIDSource, _ = sym.GetSecurityIDSource()
|
||||||
currency, _ = sym.GetCurrency()
|
currency, _ = sym.GetCurrency()
|
||||||
|
side, _ = sym.GetSide()
|
||||||
}
|
}
|
||||||
|
|
||||||
price := decimal.NewFromFloat(99.6)
|
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())
|
slog.Error("handleQuoteRequest: failed to send quote", "quoteReqID", quoteReqID, "error", sendErr.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,5 +28,10 @@ type OrderStore interface {
|
|||||||
|
|
||||||
// FIXSender is the port for sending FIX messages back to clients.
|
// FIXSender is the port for sending FIX messages back to clients.
|
||||||
type FIXSender interface {
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user