package com.quantai.trader.domain; import static com.quantai.trader.util.TraderNumbers.*; import java.math.BigDecimal; public record TraderPmConfig( String pmConfigVersion, OpenRuleConfig open, AddRuleConfig add, ExitRuleConfig exit, SizingConfig sizing ) { public TraderPmConfig { pmConfigVersion = requiredText(pmConfigVersion, "pmConfigVersion"); open = java.util.Objects.requireNonNull(open, "open config is required"); add = java.util.Objects.requireNonNull(add, "add config is required"); exit = java.util.Objects.requireNonNull(exit, "exit config is required"); sizing = java.util.Objects.requireNonNull(sizing, "sizing config is required"); } public record OpenRuleConfig( BigDecimal longOpenProb, BigDecimal shortOpenProb, BigDecimal minLongEntryProb, BigDecimal minShortEntryProb, BigDecimal maxMarketRiskProb, BigDecimal minExpectedEdgeBps, BigDecimal minDirectionMargin, BigDecimal minLiquidityCapacityRatio, BigDecimal maxOodScore ) { public OpenRuleConfig { longOpenProb = probability(longOpenProb, "open.longOpenProb"); shortOpenProb = probability(shortOpenProb, "open.shortOpenProb"); minLongEntryProb = probability(minLongEntryProb, "open.minLongEntryProb"); minShortEntryProb = probability(minShortEntryProb, "open.minShortEntryProb"); maxMarketRiskProb = probability(maxMarketRiskProb, "open.maxMarketRiskProb"); minExpectedEdgeBps = required(minExpectedEdgeBps, "open.minExpectedEdgeBps"); minDirectionMargin = nonNegative(minDirectionMargin, "open.minDirectionMargin"); minLiquidityCapacityRatio = nonNegative(minLiquidityCapacityRatio, "open.minLiquidityCapacityRatio"); maxOodScore = probability(maxOodScore, "open.maxOodScore"); } } public record AddRuleConfig( BigDecimal minLongProb, BigDecimal minShortProb, BigDecimal minContinueProb, BigDecimal minEntryProb, BigDecimal maxExitProb, BigDecimal maxMarketRiskProb, BigDecimal maxPositionRiskProb, BigDecimal minExpectedEdgeBps, BigDecimal minContinueVsExitEdgeBps, BigDecimal minLiquidityCapacityRatio, BigDecimal minPostTradeLiquidationBufferBps, int maxAddCount, long cooldownMinutes ) { public AddRuleConfig { minLongProb = probability(minLongProb, "add.minLongProb"); minShortProb = probability(minShortProb, "add.minShortProb"); minContinueProb = probability(minContinueProb, "add.minContinueProb"); minEntryProb = probability(minEntryProb, "add.minEntryProb"); maxExitProb = probability(maxExitProb, "add.maxExitProb"); maxMarketRiskProb = probability(maxMarketRiskProb, "add.maxMarketRiskProb"); maxPositionRiskProb = probability(maxPositionRiskProb, "add.maxPositionRiskProb"); minExpectedEdgeBps = required(minExpectedEdgeBps, "add.minExpectedEdgeBps"); minContinueVsExitEdgeBps = required(minContinueVsExitEdgeBps, "add.minContinueVsExitEdgeBps"); minLiquidityCapacityRatio = nonNegative(minLiquidityCapacityRatio, "add.minLiquidityCapacityRatio"); minPostTradeLiquidationBufferBps = nonNegative(minPostTradeLiquidationBufferBps, "add.minPostTradeLiquidationBufferBps"); if (maxAddCount < 0 || cooldownMinutes < 0) { throw new IllegalArgumentException("add count and cooldown must be >= 0"); } } } public record ExitRuleConfig( BigDecimal closeExitProb, BigDecimal closePositionRiskProb, BigDecimal closeMarketRiskProb, BigDecimal closeContinueMax, BigDecimal reduceAdverseMoveProb, BigDecimal reduceContinueMin, BigDecimal reduceContinueMax, BigDecimal minProfitForReduceBps, BigDecimal maxPositionPathRiskBps ) { public ExitRuleConfig { closeExitProb = probability(closeExitProb, "exit.closeExitProb"); closePositionRiskProb = probability(closePositionRiskProb, "exit.closePositionRiskProb"); closeMarketRiskProb = probability(closeMarketRiskProb, "exit.closeMarketRiskProb"); closeContinueMax = probability(closeContinueMax, "exit.closeContinueMax"); reduceAdverseMoveProb = probability(reduceAdverseMoveProb, "exit.reduceAdverseMoveProb"); reduceContinueMin = probability(reduceContinueMin, "exit.reduceContinueMin"); reduceContinueMax = probability(reduceContinueMax, "exit.reduceContinueMax"); minProfitForReduceBps = nonNegative(minProfitForReduceBps, "exit.minProfitForReduceBps"); maxPositionPathRiskBps = nonNegative(maxPositionPathRiskBps, "exit.maxPositionPathRiskBps"); } } public record SizingConfig( BigDecimal baseRatio, BigDecimal minInitialRatio, BigDecimal maxSingleLegRatio, BigDecimal minAddRatio, BigDecimal maxAddRatio, BigDecimal maxTotalPositionRatio, BigDecimal minEdgeBps, BigDecimal maxLossPerTradeBps, BigDecimal maxLiquidityUsageRatio, BigDecimal uncertaintyPenaltyMultiplier, BigDecimal minPostTradeLiquidationBufferBps ) { public SizingConfig { baseRatio = positive(baseRatio, "sizing.baseRatio"); minInitialRatio = nonNegative(minInitialRatio, "sizing.minInitialRatio"); maxSingleLegRatio = positive(maxSingleLegRatio, "sizing.maxSingleLegRatio"); minAddRatio = nonNegative(minAddRatio, "sizing.minAddRatio"); maxAddRatio = nonNegative(maxAddRatio, "sizing.maxAddRatio"); maxTotalPositionRatio = positive(maxTotalPositionRatio, "sizing.maxTotalPositionRatio"); minEdgeBps = required(minEdgeBps, "sizing.minEdgeBps"); maxLossPerTradeBps = positive(maxLossPerTradeBps, "sizing.maxLossPerTradeBps"); maxLiquidityUsageRatio = positive(maxLiquidityUsageRatio, "sizing.maxLiquidityUsageRatio"); uncertaintyPenaltyMultiplier = nonNegative(uncertaintyPenaltyMultiplier, "sizing.uncertaintyPenaltyMultiplier"); minPostTradeLiquidationBufferBps = nonNegative(minPostTradeLiquidationBufferBps, "sizing.minPostTradeLiquidationBufferBps"); } } }