231 lines
6.2 KiB
Go
231 lines
6.2 KiB
Go
// Package fix implements the QuickFIX initiator application.
|
|
package fix
|
|
|
|
import (
|
|
"log/slog"
|
|
|
|
"quantex.com/qfixdpl/quickfix"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/executionack"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/executionreport"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quote"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoteack"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoterequest"
|
|
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoteresponse"
|
|
"quantex.com/qfixdpl/quickfix/gen/tag"
|
|
"quantex.com/qfixdpl/src/domain"
|
|
)
|
|
|
|
type application struct {
|
|
router *quickfix.MessageRouter
|
|
notifier domain.Notifier
|
|
onLogon func(quickfix.SessionID)
|
|
onLogout func(quickfix.SessionID)
|
|
onQuote func(quote.Quote, quickfix.SessionID)
|
|
onQuoteRequest func(quoterequest.QuoteRequest, quickfix.SessionID)
|
|
onQuoteAck func(quoteack.QuoteAck, quickfix.SessionID)
|
|
onQuoteResponse func(quoteresponse.QuoteResponse, quickfix.SessionID)
|
|
onExecutionReport func(executionreport.ExecutionReport, quickfix.SessionID)
|
|
onExecutionAck func(executionack.ExecutionAck, quickfix.SessionID)
|
|
onRawMessage func(direction string, msg *quickfix.Message)
|
|
}
|
|
|
|
func newApplication(n domain.Notifier) *application {
|
|
app := &application{
|
|
router: quickfix.NewMessageRouter(),
|
|
notifier: n,
|
|
}
|
|
|
|
app.router.AddRoute(quote.Route(app.handleQuote))
|
|
app.router.AddRoute(quoteack.Route(app.handleQuoteAck))
|
|
app.router.AddRoute(quoterequest.Route(app.handleQuoteRequest))
|
|
app.router.AddRoute(quoteresponse.Route(app.handleQuoteResponse))
|
|
app.router.AddRoute(executionack.Route(app.handleExecutionAck))
|
|
app.router.AddRoute(executionreport.Route(app.handleExecutionReport))
|
|
|
|
return app
|
|
}
|
|
|
|
func (a *application) OnCreate(sessionID quickfix.SessionID) {
|
|
slog.Info("FIX session created", "session", sessionID.String())
|
|
}
|
|
|
|
func (a *application) OnLogon(sessionID quickfix.SessionID) {
|
|
slog.Info("FIX session logged on", "session", sessionID.String())
|
|
if a.onLogon != nil {
|
|
a.onLogon(sessionID)
|
|
}
|
|
}
|
|
|
|
func (a *application) OnLogout(sessionID quickfix.SessionID) {
|
|
slog.Info("FIX session logged out", "session", sessionID.String())
|
|
|
|
go a.notifier.SendMsg(domain.MessageChannelError, "Logout", domain.MessageStatusWarning, nil)
|
|
|
|
if a.onLogout != nil {
|
|
a.onLogout(sessionID)
|
|
}
|
|
}
|
|
|
|
func (a *application) ToAdmin(_ *quickfix.Message, _ quickfix.SessionID) {}
|
|
|
|
func (a *application) ToApp(msg *quickfix.Message, _ quickfix.SessionID) error {
|
|
if a.onRawMessage != nil {
|
|
a.onRawMessage("OUT", msg)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) FromAdmin(_ *quickfix.Message, _ quickfix.SessionID) quickfix.MessageRejectError {
|
|
return nil
|
|
}
|
|
|
|
func (a *application) FromApp(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
beginString, _ := msg.Header.GetBytes(tag.BeginString)
|
|
msgType, _ := msg.Header.GetBytes(tag.MsgType)
|
|
|
|
var applVerID quickfix.FIXString
|
|
msg.Header.GetField(tag.ApplVerID, &applVerID)
|
|
|
|
slog.Info("FIX FromApp received",
|
|
"beginString", string(beginString),
|
|
"msgType", string(msgType),
|
|
"applVerID", string(applVerID),
|
|
"session", sessionID.String(),
|
|
"rawMsg", msg.String(),
|
|
)
|
|
|
|
if a.onRawMessage != nil {
|
|
a.onRawMessage("IN", msg)
|
|
}
|
|
|
|
rejErr := a.router.Route(msg, sessionID)
|
|
if rejErr != nil {
|
|
slog.Error("FIX FromApp routing failed",
|
|
"msgType", string(msgType),
|
|
"error", rejErr.Error(),
|
|
"isBusinessReject", rejErr.IsBusinessReject(),
|
|
)
|
|
}
|
|
|
|
return rejErr
|
|
}
|
|
|
|
func (a *application) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
quoteReqID, err := msg.GetQuoteReqID()
|
|
if err != nil {
|
|
slog.Error("QuoteRequest missing QuoteReqID", "error", err.Error())
|
|
return err
|
|
}
|
|
|
|
slog.Info("QuoteRequest received",
|
|
"quoteReqID", quoteReqID,
|
|
"session", sessionID.String(),
|
|
)
|
|
|
|
if a.onQuoteRequest != nil {
|
|
a.onQuoteRequest(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) handleQuoteAck(msg quoteack.QuoteAck, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
quoteReqID, _ := msg.GetQuoteReqID()
|
|
quoteID, _ := msg.GetQuoteID()
|
|
status, _ := msg.GetQuoteAckStatus()
|
|
text, _ := msg.GetText()
|
|
|
|
slog.Info("QuoteAck received",
|
|
"quoteReqID", quoteReqID,
|
|
"quoteID", quoteID,
|
|
"quoteAckStatus", status,
|
|
"text", text,
|
|
"session", sessionID.String(),
|
|
)
|
|
|
|
if a.onQuoteAck != nil {
|
|
a.onQuoteAck(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) handleQuote(msg quote.Quote, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
quoteID, err := msg.GetQuoteID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
symbol, _ := msg.GetSymbol()
|
|
|
|
slog.Info("Quote received", "quoteID", quoteID, "symbol", symbol, "session", sessionID.String())
|
|
|
|
if a.onQuote != nil {
|
|
a.onQuote(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) handleQuoteResponse(msg quoteresponse.QuoteResponse, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
quoteRespID, _ := msg.GetQuoteRespID()
|
|
quoteReqID, _ := msg.GetQuoteReqID()
|
|
quoteRespType, _ := msg.GetQuoteRespType()
|
|
|
|
slog.Info("QuoteResponse received",
|
|
"quoteRespID", quoteRespID,
|
|
"quoteReqID", quoteReqID,
|
|
"quoteRespType", quoteRespType,
|
|
"session", sessionID.String(),
|
|
)
|
|
|
|
if a.onQuoteResponse != nil {
|
|
a.onQuoteResponse(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) handleExecutionAck(msg executionack.ExecutionAck, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
execID, _ := msg.GetExecID()
|
|
orderID, _ := msg.GetOrderID()
|
|
status, _ := msg.GetExecAckStatus()
|
|
|
|
slog.Info("ExecutionAck received",
|
|
"execID", execID,
|
|
"orderID", orderID,
|
|
"execAckStatus", status,
|
|
"session", sessionID.String(),
|
|
)
|
|
|
|
if a.onExecutionAck != nil {
|
|
a.onExecutionAck(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *application) handleExecutionReport(msg executionreport.ExecutionReport, sessionID quickfix.SessionID) quickfix.MessageRejectError {
|
|
execID, _ := msg.GetExecID()
|
|
orderID, _ := msg.GetOrderID()
|
|
listID, _ := msg.GetListID()
|
|
execType, _ := msg.GetExecType()
|
|
ordStatus, _ := msg.GetOrdStatus()
|
|
|
|
slog.Info("ExecutionReport received",
|
|
"execID", execID,
|
|
"orderID", orderID,
|
|
"listID", listID,
|
|
"execType", execType,
|
|
"ordStatus", ordStatus,
|
|
"session", sessionID.String(),
|
|
)
|
|
|
|
if a.onExecutionReport != nil {
|
|
a.onExecutionReport(msg, sessionID)
|
|
}
|
|
|
|
return nil
|
|
}
|