diff --git a/decision/engine.go b/decision/engine.go index a96db8aa..ddf0568a 100644 --- a/decision/engine.go +++ b/decision/engine.go @@ -278,6 +278,8 @@ func GetFullDecisionWithStrategy(ctx *Context, mcpClient mcp.AIClient, engine *S ctx.Account.TotalEquity, riskConfig.BTCETHMaxLeverage, riskConfig.AltcoinMaxLeverage, + riskConfig.BTCETHMaxPositionValueRatio, + riskConfig.AltcoinMaxPositionValueRatio, ) if decision != nil { @@ -1297,7 +1299,7 @@ func formatFloatSlice(values []float64) string { // AI Response Parsing // ============================================================================ -func parseFullDecisionResponse(aiResponse string, accountEquity float64, btcEthLeverage, altcoinLeverage int) (*FullDecision, error) { +func parseFullDecisionResponse(aiResponse string, accountEquity float64, btcEthLeverage, altcoinLeverage int, btcEthPosRatio, altcoinPosRatio float64) (*FullDecision, error) { cotTrace := extractCoTTrace(aiResponse) decisions, err := extractDecisions(aiResponse) @@ -1308,7 +1310,7 @@ func parseFullDecisionResponse(aiResponse string, accountEquity float64, btcEthL }, fmt.Errorf("failed to extract decisions: %w", err) } - if err := validateDecisions(decisions, accountEquity, btcEthLeverage, altcoinLeverage); err != nil { + if err := validateDecisions(decisions, accountEquity, btcEthLeverage, altcoinLeverage, btcEthPosRatio, altcoinPosRatio); err != nil { return &FullDecision{ CoTTrace: cotTrace, Decisions: decisions, @@ -1474,16 +1476,16 @@ func compactArrayOpen(s string) string { // Decision Validation // ============================================================================ -func validateDecisions(decisions []Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int) error { +func validateDecisions(decisions []Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int, btcEthPosRatio, altcoinPosRatio float64) error { for i, decision := range decisions { - if err := validateDecision(&decision, accountEquity, btcEthLeverage, altcoinLeverage); err != nil { + if err := validateDecision(&decision, accountEquity, btcEthLeverage, altcoinLeverage, btcEthPosRatio, altcoinPosRatio); err != nil { return fmt.Errorf("decision #%d validation failed: %w", i+1, err) } } return nil } -func validateDecision(d *Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int) error { +func validateDecision(d *Decision, accountEquity float64, btcEthLeverage, altcoinLeverage int, btcEthPosRatio, altcoinPosRatio float64) error { validActions := map[string]bool{ "open_long": true, "open_short": true, @@ -1499,10 +1501,12 @@ func validateDecision(d *Decision, accountEquity float64, btcEthLeverage, altcoi if d.Action == "open_long" || d.Action == "open_short" { maxLeverage := altcoinLeverage - maxPositionValue := accountEquity * 1.5 + posRatio := altcoinPosRatio + maxPositionValue := accountEquity * posRatio if d.Symbol == "BTCUSDT" || d.Symbol == "ETHUSDT" { maxLeverage = btcEthLeverage - maxPositionValue = accountEquity * 10 + posRatio = btcEthPosRatio + maxPositionValue = accountEquity * posRatio } if d.Leverage <= 0 { @@ -1533,9 +1537,9 @@ func validateDecision(d *Decision, accountEquity float64, btcEthLeverage, altcoi tolerance := maxPositionValue * 0.01 if d.PositionSizeUSD > maxPositionValue+tolerance { if d.Symbol == "BTCUSDT" || d.Symbol == "ETHUSDT" { - return fmt.Errorf("BTC/ETH single coin position value cannot exceed %.0f USDT (10x account equity), actual: %.0f", maxPositionValue, d.PositionSizeUSD) + return fmt.Errorf("BTC/ETH single coin position value cannot exceed %.0f USDT (%.1fx account equity), actual: %.0f", maxPositionValue, posRatio, d.PositionSizeUSD) } else { - return fmt.Errorf("altcoin single coin position value cannot exceed %.0f USDT (1.5x account equity), actual: %.0f", maxPositionValue, d.PositionSizeUSD) + return fmt.Errorf("altcoin single coin position value cannot exceed %.0f USDT (%.1fx account equity), actual: %.0f", maxPositionValue, posRatio, d.PositionSizeUSD) } } if d.StopLoss <= 0 || d.TakeProfit <= 0 { diff --git a/decision/validate_test.go b/decision/validate_test.go index 3f2da737..a04f1642 100644 --- a/decision/validate_test.go +++ b/decision/validate_test.go @@ -83,7 +83,8 @@ func TestLeverageFallback(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := validateDecision(&tt.decision, tt.accountEquity, tt.btcEthLeverage, tt.altcoinLeverage) + // Use default position value ratios for testing (10x for BTC/ETH, 1.5x for altcoins) + err := validateDecision(&tt.decision, tt.accountEquity, tt.btcEthLeverage, tt.altcoinLeverage, 10.0, 1.5) // Check error status if (err != nil) != tt.wantError {