TradeStatistics
Tracks trading statistics for the session. Thread-safe through atomic operations and volatile fields.
TradeStatistics.java
package com.bookmap.ordermanagement.model;
/**
* Tracks trading statistics for the session.
*
* Thread-safe through atomic operations and volatile fields.
*/
public class TradeStatistics {
// Trade counts
private volatile int totalTrades;
private volatile int winningTrades;
private volatile int losingTrades;
private volatile int longTrades;
private volatile int shortTrades;
// P&L tracking
private volatile double totalPnLTicks;
private volatile double grossProfitTicks;
private volatile double grossLossTicks;
private volatile double largestWinTicks;
private volatile double largestLossTicks;
// Order counts
private volatile int totalOrdersSent;
private volatile int totalFills;
private volatile int totalCancellations;
private volatile int totalRejections;
private volatile int blockedByGuards;
/**
* Creates a new statistics tracker.
*/
public TradeStatistics() {
reset();
}
// =========================================================================
// Recording Methods
// =========================================================================
/**
* Records a completed trade.
*
* @param family The completed family
* @param tickSize Tick size for P&L calculation
*/
public synchronized void recordTrade(OrderFamily family, double tickSize) {
totalTrades++;
if (family.isLong()) {
longTrades++;
} else {
shortTrades++;
}
double pnlTicks = family.calculatePnLTicks(tickSize);
totalPnLTicks += pnlTicks;
if (pnlTicks > 0) {
winningTrades++;
grossProfitTicks += pnlTicks;
if (pnlTicks > largestWinTicks) {
largestWinTicks = pnlTicks;
}
} else if (pnlTicks < 0) {
losingTrades++;
grossLossTicks += Math.abs(pnlTicks);
if (Math.abs(pnlTicks) > largestLossTicks) {
largestLossTicks = Math.abs(pnlTicks);
}
}
}
/**
* Records an order sent.
*/
public synchronized void recordOrderSent() {
totalOrdersSent++;
}
/**
* Records a fill.
*/
public synchronized void recordFill() {
totalFills++;
}
/**
* Records a cancellation.
*/
public synchronized void recordCancellation() {
totalCancellations++;
}
/**
* Records a rejection.
*/
public synchronized void recordRejection() {
totalRejections++;
}
/**
* Records an order blocked by guards.
*/
public synchronized void recordBlockedByGuard() {
blockedByGuards++;
}
// =========================================================================
// Calculated Metrics
// =========================================================================
/**
* Returns the win rate as a percentage (0-100).
*/
public double getWinRate() {
if (totalTrades == 0) return 0.0;
return (double) winningTrades / totalTrades * 100.0;
}
/**
* Returns the profit factor (gross profit / gross loss).
*/
public double getProfitFactor() {
if (grossLossTicks == 0) {
return grossProfitTicks > 0 ? Double.POSITIVE_INFINITY : 0.0;
}
return grossProfitTicks / grossLossTicks;
}
/**
* Returns the average P&L per trade in ticks.
*/
public double getAveragePnLPerTrade() {
if (totalTrades == 0) return 0.0;
return totalPnLTicks / totalTrades;
}
/**
* Returns the average winning trade in ticks.
*/
public double getAverageWin() {
if (winningTrades == 0) return 0.0;
return grossProfitTicks / winningTrades;
}
/**
* Returns the average losing trade in ticks.
*/
public double getAverageLoss() {
if (losingTrades == 0) return 0.0;
return grossLossTicks / losingTrades;
}
// =========================================================================
// Getters
// =========================================================================
public int getTotalTrades() { return totalTrades; }
public int getWinningTrades() { return winningTrades; }
public int getLosingTrades() { return losingTrades; }
public int getLongTrades() { return longTrades; }
public int getShortTrades() { return shortTrades; }
public double getTotalPnLTicks() { return totalPnLTicks; }
public double getGrossProfitTicks() { return grossProfitTicks; }
public double getGrossLossTicks() { return grossLossTicks; }
public double getLargestWinTicks() { return largestWinTicks; }
public double getLargestLossTicks() { return largestLossTicks; }
public int getTotalOrdersSent() { return totalOrdersSent; }
public int getTotalFills() { return totalFills; }
public int getTotalCancellations() { return totalCancellations; }
public int getTotalRejections() { return totalRejections; }
public int getBlockedByGuards() { return blockedByGuards; }
// =========================================================================
// Reset and Formatting
// =========================================================================
/**
* Resets all statistics.
*/
public synchronized void reset() {
totalTrades = 0;
winningTrades = 0;
losingTrades = 0;
longTrades = 0;
shortTrades = 0;
totalPnLTicks = 0.0;
grossProfitTicks = 0.0;
grossLossTicks = 0.0;
largestWinTicks = 0.0;
largestLossTicks = 0.0;
totalOrdersSent = 0;
totalFills = 0;
totalCancellations = 0;
totalRejections = 0;
blockedByGuards = 0;
}
/**
* Returns a summary string for logging.
*/
public String toSummary() {
return String.format(
"Trades: %d (W:%d L:%d) | WinRate: %.1f%% | PnL: %.1f ticks | PF: %.2f",
totalTrades, winningTrades, losingTrades,
getWinRate(), totalPnLTicks, getProfitFactor());
}
/**
* Returns a detailed multi-line report.
*/
public String toDetailedReport() {
StringBuilder sb = new StringBuilder();
sb.append("=======================================\n");
sb.append(" TRADING STATISTICS \n");
sb.append("=======================================\n");
sb.append(String.format("Total Trades: %d\n", totalTrades));
sb.append(String.format(" Winning: %d\n", winningTrades));
sb.append(String.format(" Losing: %d\n", losingTrades));
sb.append(String.format(" Long: %d\n", longTrades));
sb.append(String.format(" Short: %d\n", shortTrades));
sb.append("---------------------------------------\n");
sb.append(String.format("Win Rate: %.1f%%\n", getWinRate()));
sb.append(String.format("Profit Factor: %.2f\n", getProfitFactor()));
sb.append("---------------------------------------\n");
sb.append(String.format("Total P&L: %.1f ticks\n", totalPnLTicks));
sb.append(String.format("Gross Profit: %.1f ticks\n", grossProfitTicks));
sb.append(String.format("Gross Loss: %.1f ticks\n", grossLossTicks));
sb.append(String.format("Avg Win: %.1f ticks\n", getAverageWin()));
sb.append(String.format("Avg Loss: %.1f ticks\n", getAverageLoss()));
sb.append(String.format("Largest Win: %.1f ticks\n", largestWinTicks));
sb.append(String.format("Largest Loss: %.1f ticks\n", largestLossTicks));
sb.append("---------------------------------------\n");
sb.append(String.format("Orders Sent: %d\n", totalOrdersSent));
sb.append(String.format("Fills: %d\n", totalFills));
sb.append(String.format("Cancellations: %d\n", totalCancellations));
sb.append(String.format("Rejections: %d\n", totalRejections));
sb.append(String.format("Blocked by Guards: %d\n", blockedByGuards));
sb.append("=======================================\n");
return sb.toString();
}
}