Add Quickfix library #1

Merged
RamiroPaz merged 9 commits from quickfix into develop 2026-03-12 15:32:10 +00:00
1241 changed files with 1408902 additions and 261 deletions
Showing only changes of commit 7e26addd80 - Show all commits

117
quickfix/file_log.go Normal file
View File

@ -0,0 +1,117 @@
// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact ask@quickfixengine.org if any conditions of this licensing
// are not clear to you.
package quickfix
import (
"fmt"
"log"
"os"
"path"
"quantex.com/qfixdpl/quickfix/config"
)
type fileLog struct {
eventLogger *log.Logger
messageLogger *log.Logger
}
func (l fileLog) OnIncoming(msg []byte) {
l.messageLogger.Print(string(msg))
}
func (l fileLog) OnOutgoing(msg []byte) {
l.messageLogger.Print(string(msg))
}
func (l fileLog) OnEvent(msg string) {
l.eventLogger.Print(msg)
}
func (l fileLog) OnEventf(format string, v ...interface{}) {
l.eventLogger.Printf(format, v...)
}
type fileLogFactory struct {
globalLogPath string
sessionLogPaths map[SessionID]string
}
// NewFileLogFactory creates an instance of LogFactory that writes messages and events to file.
// The location of global and session log files is configured via FileLogPath.
func NewFileLogFactory(settings *Settings) (LogFactory, error) {
logFactory := fileLogFactory{}
var err error
if logFactory.globalLogPath, err = settings.GlobalSettings().Setting(config.FileLogPath); err != nil {
return logFactory, err
}
logFactory.sessionLogPaths = make(map[SessionID]string)
for sid, sessionSettings := range settings.SessionSettings() {
logPath, err := sessionSettings.Setting(config.FileLogPath)
if err != nil {
return logFactory, err
}
logFactory.sessionLogPaths[sid] = logPath
}
return logFactory, nil
}
func newFileLog(prefix string, logPath string) (fileLog, error) {
l := fileLog{}
eventLogName := path.Join(logPath, prefix+".event.current.log")
messageLogName := path.Join(logPath, prefix+".messages.current.log")
if err := os.MkdirAll(logPath, os.ModePerm); err != nil {
return l, err
}
fileFlags := os.O_RDWR | os.O_CREATE | os.O_APPEND
eventFile, err := os.OpenFile(eventLogName, fileFlags, os.ModePerm)
if err != nil {
return l, err
}
messageFile, err := os.OpenFile(messageLogName, fileFlags, os.ModePerm)
if err != nil {
return l, err
}
logFlag := log.Ldate | log.Ltime | log.Lmicroseconds | log.LUTC
l.eventLogger = log.New(eventFile, "", logFlag)
l.messageLogger = log.New(messageFile, "", logFlag)
return l, nil
}
func (f fileLogFactory) Create() (Log, error) {
return newFileLog("GLOBAL", f.globalLogPath)
}
func (f fileLogFactory) CreateSessionLog(sessionID SessionID) (Log, error) {
logPath, ok := f.sessionLogPaths[sessionID]
if !ok {
return nil, fmt.Errorf("logger not defined for %v", sessionID)
}
prefix := sessionIDFilenamePrefix(sessionID)
return newFileLog(prefix, logPath)
}

56
quickfix/fileutil.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright (c) quickfixengine.org All rights reserved.
//
// This file may be distributed under the terms of the quickfixengine.org
// license as defined by quickfixengine.org and appearing in the file
// LICENSE included in the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.
//
// See http://www.quickfixengine.org/LICENSE for licensing information.
//
// Contact ask@quickfixengine.org if any conditions of this licensing
// are not clear to you.
package quickfix
import (
"fmt"
"os"
"strings"
)
func sessionIDFilenamePrefix(s SessionID) string {
sender := []string{s.SenderCompID}
if s.SenderSubID != "" {
sender = append(sender, s.SenderSubID)
}
if s.SenderLocationID != "" {
sender = append(sender, s.SenderLocationID)
}
target := []string{s.TargetCompID}
if s.TargetSubID != "" {
target = append(target, s.TargetSubID)
}
if s.TargetLocationID != "" {
target = append(target, s.TargetLocationID)
}
fname := []string{s.BeginString, strings.Join(sender, "_"), strings.Join(target, "_")}
if s.Qualifier != "" {
fname = append(fname, s.Qualifier)
}
return strings.Join(fname, "-")
}
// openOrCreateFile opens a file for reading and writing, creating it if necessary.
func openOrCreateFile(fname string, perm os.FileMode) (f *os.File, err error) {
if f, err = os.OpenFile(fname, os.O_RDWR, perm); err != nil {
if f, err = os.OpenFile(fname, os.O_RDWR|os.O_CREATE, perm); err != nil {
return nil, fmt.Errorf("error opening or creating file: %s: %s", fname, err.Error())
}
}
return f, nil
}

View File

@ -7,6 +7,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/rs/zerolog/log"
"github.com/shopspring/decimal" "github.com/shopspring/decimal"
"quantex.com/qfixdpl/quickfix" "quantex.com/qfixdpl/quickfix"
@ -14,6 +15,7 @@ import (
"quantex.com/qfixdpl/quickfix/gen/field" "quantex.com/qfixdpl/quickfix/gen/field"
"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quote" "quantex.com/qfixdpl/quickfix/gen/fix50sp2/quote"
"quantex.com/qfixdpl/src/app" "quantex.com/qfixdpl/src/app"
"quantex.com/qfixdpl/src/common/tracerr"
"quantex.com/qfixdpl/src/domain" "quantex.com/qfixdpl/src/domain"
) )
@ -55,7 +57,13 @@ func (m *Manager) Start() error {
} }
storeFactory := quickfix.NewMemoryStoreFactory() storeFactory := quickfix.NewMemoryStoreFactory()
logFactory := quickfix.NewNullLogFactory() logFactory, err := quickfix.NewFileLogFactory(settings)
if err != nil {
err = tracerr.Errorf("error creating file log factory: %s", err)
log.Error().Msg(err.Error())
return err
}
initiator, err := quickfix.NewInitiator(fixApp, storeFactory, settings, logFactory) initiator, err := quickfix.NewInitiator(fixApp, storeFactory, settings, logFactory)
if err != nil { if err != nil {