This commit is contained in:
Ramiro Paz
2026-05-11 12:34:55 -03:00
parent 45fad9de6c
commit 99c7f8ccb0
8 changed files with 69 additions and 49 deletions

View File

@ -127,7 +127,7 @@ func parseScalar(raw []byte, fixType string) interface{} {
s := string(raw)
switch fixType {
case "INT", "SEQNUM", "LENGTH", "DAYOFMONTH":
case "INT", "SEQNUM", "LENGTH":
var v quickfix.FIXInt
if err := v.Read(raw); err == nil {
return int(v)

View File

@ -25,6 +25,7 @@ func GetMap(fieldMap FieldMap) map[string]interface{} {
result := map[string]interface{}{}
for f, v := range fieldMap {
slog.Info("try to parse fieldMap: %+v, value: %+v", f, v)
k, val := GetKeyValue(f, v)
result[k] = val
}
@ -42,7 +43,7 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
fMapLst, ok := value.([]FieldMap)
if !ok {
err := tracerr.Errorf("could not parse as []FieldMap, value: %+v", value)
err := tracerr.Errorf("could not parse as []FieldMap, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
@ -54,23 +55,15 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
case "BOOLEAN":
b, ok := value.(bool)
if !ok {
err := tracerr.Errorf("could not parse as bool, value: %+v", value)
err := tracerr.Errorf("could not parse as bool, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
val = b
case "INT":
case "INT", "LENGTH", "SEQNUM":
i, ok := value.(int)
if !ok {
err := tracerr.Errorf("could not parse as int, value: %+v", value)
slog.Error(err.Error())
}
val = i
case "SEQNUM":
i, ok := value.(int)
if !ok {
err := tracerr.Errorf("could not parse as int, value: %+v", value)
err := tracerr.Errorf("could not parse as int, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
@ -78,7 +71,7 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
case "UTCTIMESTAMP":
t, ok := value.(time.Time)
if !ok {
err := tracerr.Errorf("could not parse as Time, value: %+v", value)
err := tracerr.Errorf("could not parse as Time, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
@ -86,7 +79,7 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
case "STRING":
s, ok := value.(string)
if !ok {
err := tracerr.Errorf("could not parse as string, value: %+v", value)
err := tracerr.Errorf("could not parse as string, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
@ -94,7 +87,7 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
case "CHAR":
s, ok := value.(string)
if !ok {
err := tracerr.Errorf("could not parse as string, value: %+v", value)
err := tracerr.Errorf("could not parse as string, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}
@ -102,7 +95,7 @@ func GetKeyValue(f FixField, value FieldValue) (key string, val interface{}) {
default:
s, ok := value.(string)
if !ok {
err := tracerr.Errorf("could not parse as string, value: %+v", value)
err := tracerr.Errorf("could not parse as string, value: %+v, key: %s", value, key)
slog.Error(err.Error())
}

View File

@ -201,13 +201,25 @@ func (m *Manager) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID qu
quoteReqID := parsed.QuoteReqID
if quoteReqID == "" {
err := tracerr.Errorf("handleQuoteRequest: missing QuoteReqID")
m.notify.SendMsg(
domain.MessageChannelError,
"quoteReqID missing in quote request",
domain.MessageStatusWarning,
nil,
)
err := tracerr.Errorf("handleQuoteRequest, missing QuoteReqID, quoteRequest: %+v", parsed)
slog.Error(err.Error())
return
}
// Validate LST_ prefix for List Trading flow.
if !strings.HasPrefix(quoteReqID, "LST_") {
m.notify.SendMsg(
domain.MessageChannelError,
"quoteReqID ("+quoteReqID+") missing LST_ prefix",
domain.MessageStatusWarning,
nil,
)
slog.Warn("handleQuoteRequest: QuoteReqID missing LST_ prefix, ignoring", "quoteReqID", quoteReqID)
return
}
@ -225,20 +237,8 @@ func (m *Manager) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID qu
}
slog.Info("handleQuoteRequest: NoRelatedSym keys", "quoteReqID", quoteReqID, "keys", relSymKeys)
listID := getString(relSym, "ListID")
negotiationType := getString(relSym, "NegotiationType")
ownerTraderID := getString(relSym, "OwnerTraderID")
if listID == "" {
slog.Warn("handleQuoteRequest: missing ListID", "quoteReqID", quoteReqID)
return
}
if negotiationType != "RFQ" {
slog.Warn("handleQuoteRequest: unexpected NegotiationType", "quoteReqID", quoteReqID, "negotiationType", negotiationType)
return
}
// Send QuoteStatusReport (35=AI) to acknowledge the inquiry.
if ackErr := m.sendQuoteStatusReport(quoteReqID, ownerTraderID, sessionID); ackErr != nil {
ackErr = tracerr.Errorf("handleQuoteRequest: failed to send QuoteStatusReport (quoteReqID=%s): %w", quoteReqID, ackErr)
@ -418,9 +418,7 @@ func (m *Manager) GetPendingQuoteRequests() []domain.ListTrade {
pending := make([]domain.ListTrade, 0)
for _, t := range m.trades {
if !t.Quoted {
pending = append(pending, toDomainListTrade(t))
}
pending = append(pending, toDomainListTrade(t))
}
return pending
@ -429,7 +427,6 @@ func (m *Manager) GetPendingQuoteRequests() []domain.ListTrade {
func toDomainListTrade(t *listTrade) domain.ListTrade {
out := domain.ListTrade{
QuoteRequest: t.QuoteRequest,
Quoted: t.Quoted,
}
if !t.Price.IsZero() {
out.Price = t.Price.String()
@ -447,12 +444,12 @@ func (m *Manager) SendQuote(quoteReqID string, price decimal.Decimal) error {
slog.Error(err.Error())
return err
}
if t.Quoted {
m.tradesMu.Unlock()
err := tracerr.Errorf("SendQuote: quote already sent for quoteReqID %s", quoteReqID)
slog.Error(err.Error())
return err
}
// if t.Quoted {
// m.tradesMu.Unlock()
// err := tracerr.Errorf("SendQuote: quote already sent for quoteReqID %s", quoteReqID)
// slog.Error(err.Error())
// return err
// }
sessionID := t.SessionID
if sessionID == (quickfix.SessionID{}) {
@ -465,14 +462,13 @@ func (m *Manager) SendQuote(quoteReqID string, price decimal.Decimal) error {
}
}
relSym := firstGroup(t.QuoteRequest.Body, "NoRelatedSym")
symbol := getString(relSym, "SecurityID")
sIDSource := enum.SecurityIDSource(getString(relSym, "SecurityIDSource"))
currency := getString(relSym, "Currency")
side := enum.Side(getString(relSym, "Side"))
orderQty := getDecimal(relSym, "OrderQty")
settlDate := getString(relSym, "SettlDate")
ownerTraderID := getString(relSym, "OwnerTraderID")
symbol := getString(t.QuoteRequest.Body, "SecurityID")
sIDSource := enum.SecurityIDSource(getString(t.QuoteRequest.Body, "SecurityIDSource"))
currency := getString(t.QuoteRequest.Body, "Currency")
side := enum.Side(getString(t.QuoteRequest.Body, "Side"))
orderQty := getDecimal(t.QuoteRequest.Body, "OrderQty")
settlDate := getString(t.QuoteRequest.Body, "SettlDate")
ownerTraderID := getString(t.QuoteRequest.Body, "OwnerTraderID")
m.tradesMu.Unlock()
if sIDSource != enum.SecurityIDSource_CUSIP {

View File

@ -6,7 +6,6 @@ import "time"
// ListTrade es la representacion exportada de un trade de List Trading.
type ListTrade struct {
QuoteRequest FixMessageJSON `json:"quote_request"`
Quoted bool `json:"quoted"`
Price string `json:"price,omitempty"`
}