|
|
|
|
@ -55,7 +55,7 @@ type Manager struct {
|
|
|
|
|
initiator *quickfix.Initiator
|
|
|
|
|
app *application
|
|
|
|
|
tradesMu sync.RWMutex
|
|
|
|
|
trades map[string]*postTrade
|
|
|
|
|
trades map[string]domain.TradeCaptureReport
|
|
|
|
|
store domain.PersistenceStore
|
|
|
|
|
notify domain.Notifier
|
|
|
|
|
cfg app.FIXConfig
|
|
|
|
|
@ -63,7 +63,7 @@ type Manager struct {
|
|
|
|
|
|
|
|
|
|
func NewManager(cfg app.FIXConfig, store domain.PersistenceStore, notify domain.Notifier) *Manager {
|
|
|
|
|
return &Manager{
|
|
|
|
|
trades: make(map[string]*postTrade),
|
|
|
|
|
trades: make(map[string]domain.TradeCaptureReport),
|
|
|
|
|
store: store,
|
|
|
|
|
notify: notify,
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
@ -202,7 +202,7 @@ func (m *Manager) handleTradeCaptureReport(msg tradecapturereport.TradeCaptureRe
|
|
|
|
|
twTraderID = extractPartyByRole(s, "1007")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trade := domain.Trade{
|
|
|
|
|
trade := domain.TradeCaptureReport{
|
|
|
|
|
TradeReportID: tradeReportID,
|
|
|
|
|
TradeID: tradeID,
|
|
|
|
|
ExecID: execID,
|
|
|
|
|
@ -236,43 +236,8 @@ func (m *Manager) handleTradeCaptureReport(msg tradecapturereport.TradeCaptureRe
|
|
|
|
|
// Persist structured message.
|
|
|
|
|
m.persistMessage(tradeID, parseTradeCaptureReportJSON(msg))
|
|
|
|
|
|
|
|
|
|
// Update in-memory state.
|
|
|
|
|
var status domain.PostTradeStatus
|
|
|
|
|
|
|
|
|
|
switch string(tradeReportType) {
|
|
|
|
|
case "101": // TRDCONF — trade confirmation
|
|
|
|
|
status = domain.PostTradeStatusActive
|
|
|
|
|
slog.Info("TRDCONF: trade confirmation", "tradeReportID", tradeReportID, "tradeID", tradeID)
|
|
|
|
|
case "102": // TRDBLOCK — block trade, log only
|
|
|
|
|
status = domain.PostTradeStatusActive
|
|
|
|
|
slog.Info("TRDBLOCK: block trade", "tradeReportID", tradeReportID, "tradeID", tradeID)
|
|
|
|
|
case "103": // TRDCORR — trade correction
|
|
|
|
|
status = domain.PostTradeStatusCorrected
|
|
|
|
|
slog.Info("TRDCORR: trade correction", "tradeReportID", tradeReportID, "refID", tradeReportRefID)
|
|
|
|
|
case "104": // TRDCXL — trade cancellation
|
|
|
|
|
status = domain.PostTradeStatusCancelled
|
|
|
|
|
slog.Info("TRDCXL: trade cancel", "tradeReportID", tradeReportID, "refID", tradeReportRefID)
|
|
|
|
|
case "105", "106", "107", "108": // log and ack only, no business logic
|
|
|
|
|
status = domain.PostTradeStatusActive
|
|
|
|
|
slog.Info("trade report (no business logic)", "tradeReportType", string(tradeReportType), "tradeReportID", tradeReportID)
|
|
|
|
|
default:
|
|
|
|
|
status = domain.PostTradeStatusActive
|
|
|
|
|
slog.Warn("unexpected TradeReportType", "tradeReportType", string(tradeReportType), "tradeReportID", tradeReportID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.tradesMu.Lock()
|
|
|
|
|
m.trades[tradeID] = &postTrade{
|
|
|
|
|
TradeID: tradeID,
|
|
|
|
|
TradeReportID: tradeReportID,
|
|
|
|
|
TradeReportType: string(tradeReportType),
|
|
|
|
|
Side: side,
|
|
|
|
|
LastQty: lastQty,
|
|
|
|
|
LastPx: lastPx,
|
|
|
|
|
SettlDate: settlDate,
|
|
|
|
|
TradeDate: tradeDate,
|
|
|
|
|
Status: status,
|
|
|
|
|
TWTradeID: twTradeID,
|
|
|
|
|
}
|
|
|
|
|
m.trades[tradeID] = trade
|
|
|
|
|
m.tradesMu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -451,7 +416,7 @@ func (m *Manager) loadTrades() error {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trades := make(map[string]*postTrade)
|
|
|
|
|
trades := make(map[string]domain.TradeCaptureReport)
|
|
|
|
|
|
|
|
|
|
for _, msg := range messages {
|
|
|
|
|
switch msg.JMessage.MsgType {
|
|
|
|
|
@ -466,9 +431,9 @@ func (m *Manager) loadTrades() error {
|
|
|
|
|
|
|
|
|
|
t, exists := trades[tradeID]
|
|
|
|
|
if !exists {
|
|
|
|
|
t = &postTrade{
|
|
|
|
|
t = domain.TradeCaptureReport{
|
|
|
|
|
TradeID: tradeID,
|
|
|
|
|
Status: domain.PostTradeStatusActive,
|
|
|
|
|
// Status: domain.PostTradeStatusActive,
|
|
|
|
|
}
|
|
|
|
|
trades[tradeID] = t
|
|
|
|
|
}
|
|
|
|
|
@ -503,60 +468,57 @@ func (m *Manager) loadTrades() error {
|
|
|
|
|
t.TWTradeID = v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch tradeReportType {
|
|
|
|
|
case "103": // TRDCORR
|
|
|
|
|
t.Status = domain.PostTradeStatusCorrected
|
|
|
|
|
case "104": // TRDCXL
|
|
|
|
|
t.Status = domain.PostTradeStatusCancelled
|
|
|
|
|
default:
|
|
|
|
|
if t.Status != domain.PostTradeStatusCorrected && t.Status != domain.PostTradeStatusCancelled {
|
|
|
|
|
t.Status = domain.PostTradeStatusActive
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// switch tradeReportType {
|
|
|
|
|
// case "103": // TRDCORR
|
|
|
|
|
// t.Status = domain.PostTradeStatusCorrected
|
|
|
|
|
// case "104": // TRDCXL
|
|
|
|
|
// t.Status = domain.PostTradeStatusCancelled
|
|
|
|
|
// default:
|
|
|
|
|
// if t.Status != domain.PostTradeStatusCorrected && t.Status != domain.PostTradeStatusCancelled {
|
|
|
|
|
// t.Status = domain.PostTradeStatusActive
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active := 0
|
|
|
|
|
for _, t := range trades {
|
|
|
|
|
if t.Status == domain.PostTradeStatusActive {
|
|
|
|
|
active++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// active := 0
|
|
|
|
|
// for _, t := range trades {
|
|
|
|
|
// if t.Status == domain.PostTradeStatusActive {
|
|
|
|
|
// active++
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
m.tradesMu.Lock()
|
|
|
|
|
m.trades = trades
|
|
|
|
|
m.tradesMu.Unlock()
|
|
|
|
|
|
|
|
|
|
slog.Info("recovery completed", "totalTrades", len(trades), "activeTrades", active)
|
|
|
|
|
// slog.Info("recovery completed", "totalTrades", len(trades), "activeTrades", active)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTrades returns only active trades.
|
|
|
|
|
func (m *Manager) GetTrades() []domain.PostTrade {
|
|
|
|
|
func (m *Manager) TradeCaptureReports() []domain.TradeCaptureReport {
|
|
|
|
|
m.tradesMu.RLock()
|
|
|
|
|
defer m.tradesMu.RUnlock()
|
|
|
|
|
|
|
|
|
|
var result []domain.PostTrade
|
|
|
|
|
var result []domain.TradeCaptureReport
|
|
|
|
|
|
|
|
|
|
for _, t := range m.trades {
|
|
|
|
|
if t.Status == domain.PostTradeStatusActive {
|
|
|
|
|
result = append(result, t.toPostTrade())
|
|
|
|
|
}
|
|
|
|
|
result = append(result, t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetAllTrades returns all trades regardless of status.
|
|
|
|
|
func (m *Manager) GetAllTrades() []domain.PostTrade {
|
|
|
|
|
func (m *Manager) GetAllTrades() []domain.TradeCaptureReport {
|
|
|
|
|
m.tradesMu.RLock()
|
|
|
|
|
defer m.tradesMu.RUnlock()
|
|
|
|
|
|
|
|
|
|
result := make([]domain.PostTrade, 0, len(m.trades))
|
|
|
|
|
result := make([]domain.TradeCaptureReport, 0, len(m.trades))
|
|
|
|
|
|
|
|
|
|
for _, t := range m.trades {
|
|
|
|
|
result = append(result, t.toPostTrade())
|
|
|
|
|
result = append(result, t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|